
<!DOCTYPE html>

<!--[if IE]><![endif]-->
<!--[if IE 9]> <html class="no-js ie9 lt-ie10" lang="en"> <![endif]-->
<!--[if gt IE 9]><!--> <html class="no-js" lang="en"> <!--<![endif]-->

<script>
var pendoData = {
    visitor: {
        id:          "",
        key:         "",
        package:     "2",
        template:    "portal",
        firstName:   "",
        lastName:    "",
        email:       "",
        companyName: "",
        companyNum:  "",
        role:        "standard"
    },
    account: {
        id:          "coresite",
        key:         "C6E845C68CD04E9CBED3EAA7F6E81B83",
        package:     "2"
    },
    session: {
        loggedIn:    "False",
        superUser:   "False"
    }
};
(function(apiKey){
    (function(p,e,n,d,o){var v,w,x,y,z;o=p[d]=p[d]||{};o._q=[];
    v=['initialize','identify','updateOptions','pageLoad'];for(w=0,x=v.length;w<x;++w)(function(m){
        o[m]=o[m]||function(){o._q[m===v[0]?'unshift':'push']([m].concat([].slice.call(arguments,0)));};})(v[w]);
        y=e.createElement(n);y.async=!0;y.src='https://cdn.pendo.io/agent/static/'+apiKey+'/pendo.js';
        z=e.getElementsByTagName(n)[0];z.parentNode.insertBefore(y,z);})(window,document,'script','pendo');

        pendo.initialize(pendoData);
})('53aab975-b5c0-47bb-4f37-d7849209d68c');
</script>

<head>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=2">
	
	

	<title></title>
	<meta name="description" content="">
	<meta name="keywords" content="">
		<meta name="robots" content="noindex, nofollow, noimageindex">
  <link href="https://fonts.googleapis.com/css?family=Heebo:400,500,700&display=swap" rel="stylesheet"><link rel="stylesheet" href="templates/fa/css/font-awesome.min.css">

	<link rel="shortcut icon" type="image/x-icon" href="https://d3ccrbl9fhkqmr.cloudfront.net/images/no-image.png?v=3868854232">
	<link rel="icon" type="image/png" href="" sizes="16x16" />
	<link rel="icon" type="image/png" href="" sizes="32x32" />

	<link rel="stylesheet" type="text/css" href="//cdn.datatables.net/v/dt/dt-1.10.16/cr-1.4.1/fh-3.1.3/r-2.2.0/rg-1.0.2/datatables.min.css"/>

	
		<link rel="stylesheet" href="css/bootstrap-dashboard.css?d475520">
		<link rel="stylesheet" href="css/dashboard-user.css?d475520">
		<link rel="stylesheet" href="../css/focus.css?d475520">

	
    <link rel="stylesheet" href="css/notemplate.css?d475520">


    <style>

        /* 
        ### Skins CSS Overrides
        */
        
                /* Dashboard Template Styles 
                --------------------------------------------------------------- */

                h1, h2, h3, h4, h5, h6,
                input, button, select, textarea,
                body, body.dashboard {
                    font-family: Heebo
                }

                a { 
                    color: #00A3E0; 
                }

                .text-warning,
                a.text-warning {
                    color: #8a6d3b;
                }

                .text-warning:hover {
                    color: #8a6d3b;
                }

                a.text-warning:hover {
                    color: #66512c;
                }

                .text-danger,
                a.text-danger {
                    color: #a94442;
                }

                .text-danger:hover {
                    color: #a94442;
                }

                a.text-danger:hover {
                    color: #843534;
                }

                .text-success,
                a.text-success {
                    color: #3c763d;
                }

                .text-success:hover {
                    color: #3c763d;
                }

                a.text-success:hover {
                    color: #2b542c;
                }

                .text-info,
                a.text-info {
                    color: #31708f;
                }

                .text-info:hover {
                    color: #31708f;
                }

                a.text-info:hover {
                    color: #245269;
                }

                li.active>a,
                a.active,
                a:hover,
                a:focus { 
                    color: rgb(26,188,250); 
                }

                li>a.activity-nav__link {
                    color: #333333e6;
                }

                li>a.activity-nav__link.active,
                li>a.activity-nav__link:hover,
                li>a.activity-nav__link:focus {
                    color: #333333;
                }

                .portal-home .thumbnail:hover {
                    color: rgb(26,188,250); 
                    border-color: rgb(26,188,250);
                }

                .portal-home .thumbnail:active {
                    border-color: #ddd;
                }

                h1, h2, h3, h4, h5, h6, 
                .formblock-heading, 
                legend, 
                .checkout-section-heading, 
                .checkout-section.active .checkout-section-heading { 
                    color: #444444; 
                }

                .pace .pace-progress {
                    background: #00A3E0;
                }


                /* Default buttons 
                --------------------------------------------------------------- */

                .btn-link {
                    color: #00A3E0;
                }

                .btn-link:not([disabled]):hover, 
                .btn-link:not([disabled]):focus, 
                .btn-link:not([disabled]):active, 
                .btn-link:not([disabled]).active {
                    color: rgb(26,188,250);
                }

                /* Primary buttons */
                .btn-primary, .btn-primary.button {
                    background-color: #00A3E0;
                    border-color: #00A3E0;
                    color: #ffffff;
                }

                .btn-primary:not([disabled]):hover, 
                .btn-primary:not([disabled]):focus, 
                .btn-primary:not([disabled]):active, 
                .btn-primary:not([disabled]).active, 
                .btn-primary:not([disabled]).button:hover, 
                .btn-primary:not([disabled]).button:focus, 
                .btn-primary:not([disabled]).button:active, 
                .btn-primary:not([disabled]).button.active {
                    background-color: rgb(26,188,250);
                    border-color: rgb(26,188,250);
                    color: #ffffff;
                }

                /* Secondary buttons */
                .btn:not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info), 
                .btn:not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).button {
                    background-color: #ffffff;
                    border-color: rgb(204,204,204);
                    color: #444444;
                }

                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info):hover, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info):focus, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info):active, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).active, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).button:hover, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).button:focus, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).button:active, 
                .btn:not([disabled]):not(.btn-primary):not(.btn-error):not(.btn-danger):not(.btn-warning):not(.btn-success):not(.btn-info).button.active {
                    background-color: rgb(245,245,245);
                    border-color: rgb(204,204,204);
                    color: #222222;
                }

                .list-group-item.active, 
                .list-group-item.active:hover, 
                .list-group-item.active:focus {
                    color: #ffffff !important;
                    border-color: #00A3E0 !important;
                    background-color: #00A3E0 !important;
                }

                /* Dashboard Header
                --------------------------------------------------------------- */

                .focus-header,
                .app-settings__tabs,
                .dashboard-header-1 {
                    background-color: #ffffff;
                    color: #333333;
                    border-bottom: 1px solid rgb(230,230,230);
                }

                .focus-header__exit-wrapper {
                    border-color: rgb(230,230,230);
                }

                .focus-header__exit {
                    color: #333333;
                }
                
                .focus-header__exit:focus,
                .focus-header__exit:active,
                .focus-header__exit:hover {
                    color: #333333 !important;
                    background-color:  rgb(230,230,230);
                }

                body.dashboard:not(.menu-open) .dashboard-header-1 {
                    border-left: none;
                }
                
                body.dashboard .off-canvas-hide,
                body.dashboard.-loading-dom .menu-shelf__btn-wrapper,
                .dashboard-header-1 .app-navicon {
                    color: #333333;
                    border-left: 1px solid rgb(230,230,230);
                }

                body.dashboard .off-canvas-show {
                    color: #333333;
                    border-right: 1px solid rgb(230,230,230);
                }

                @media (max-width: 480px) {
                    .dashboard-header-1 .app-logo {
                        border-right: 1px solid rgb(230,230,230);
                    }
                }

                .dashboard-header-1 .app-logo__validip-name:after {
                    background-color: rgb(230,230,230);
                }

                body.dashboard .off-canvas-hide:hover,
                .dashboard-header-1 .app-navicon:not(.app-logo):hover {
                    color: #333333;
                    border-left: 1px solid rgb(230,230,230);
                    background-color: rgb(245,245,245);
                }

                .dashboard-header-1 .app-logo:hover {
                    background-color: transparent;
                }

                body.dashboard .off-canvas-show:hover {
                    color: #333333;
                    border-right: 1px solid rgb(230,230,230);
                    background-color: rgb(245,245,245);
                }

                body.dashboard .off-canvas-hide:active,
                .dashboard-header-1 .app-navicon:not(.app-logo):active {
                    color: #333333;
                    background-color: rgb(250,250,250);
                }

                .dashboard-header-1 .app-logo:active {
                    background-color: transparent;
                }

                body.dashboard .off-canvas-show:active {
                    color: #333333;
                    background-color: rgb(250,250,250);
                }

                .dashboard-header-1 .app-navicon:not(.app-logo).active {
                    color: #333333;
                    background-color: rgb(250,250,250);
                }

                .dashboard-header-1 .app-navicon:not(.app-logo).active:hover {
                    color: #333333;
                    background-color: rgb(245,245,245);
                }

                .dashboard-header-1 .app-navicon:not(.app-logo).active:active {
                    color: #333333;
                    background-color: rgb(250,250,250);
                }

                .dashboard-header-1 .app-navicon .badge {
                    background-color: #00A3E0;
                    color: #ffffff;
                }

                #dashboard-header-1 .header__search__button {
                    background-color: #00A3E0;
                    color: #ffffff;
                }

                #dashboard-header-1 .header__search__button:hover,
                #dashboard-header-1 .header__search__button:focus {
                    color: #ffffff;
                    background-color: rgb(26,188,250);
                }

                .dashboard-header-1 .menu-drawer__lock {
                    color: #333333;
                    border: none;
                    background: none;
                }

                .dashboard-header-1 .menu-drawer__lock:hover,
                .dashboard-header-1 .menu-drawer__lock:focus,
                .dashboard-header-1 .menu-drawer__lock:active,
                .dashboard-header-1 .menu-drawer__lock.active {
                    color: #333333;
                    border: none;
                    background: none;
                }

                .app-cartqty {
                    color: #333333;
                }

                .menu-drawer__filter-search.input-search input:focus,
                code:focus, pre:focus, select:focus, textarea:focus, input:not(.btn):focus {
                    border-color: #00A3E0;
                    box-shadow: 0 0 0 2px rgba(0, 163, 224, 0.15);
                }

                .ac_results li.ac_over {
                    background-color: #00A3E0;
                }

                @media (max-width: 979px) {
                    .app-search {
                        background-color: #ffffff;
                        color: #333333;
                    }
                }


                /* Products
                --------------------------------------------------------------- */

                .prod-pricing .retail {
                    color: #00A3E0;
                }


                /* Dashboard Sidebars
                --------------------------------------------------------------- */
                
                .toolbar {
                    background-color: #000000;
                }

                @media (max-width: 480px) {
                    body:not(.menu-open) .toolbar {
                        background: none !important;
                    }
                }

                .toolbar__btn--mobile {
                    color: #333333;
                    background: #ffffff;
                }

                body.menu-open .toolbar__btn--mobile {
                    color: #ffffff;
                    background: #00A3E0;
                }

                .toolbar:before {
                    background-color: #000000;
                }

                .toolbar__btn {
                    color: #FFFFFF;
                }

                .toolbar__btn:hover {
                    background-color: rgb(56,56,56);
                }
                
                .toolbar__btn:active {
                    background-color: rgb(76,76,76);
                }
                
                .toolbar__btn.active {
                    background-color: rgb(46,46,46);
                }
                
                .toolbar__btn.active:hover {
                    background-color: rgb(56,56,56);
                }
                
                .toolbar__btn.active:active {
                    background-color: rgb(51,51,51);
                }
                
                .menu-drawer {
                    background-color: #FFFFFF;
                    color: #333333;
                    border-right: 1px solid rgb(230,230,230);
                }

                .menu-drawer .linkset>li>a {
                    color: rgba(51,51,51,0.9);
                }

                .menu-drawer .linkset>li>a:hover {
                    color: #333333;
                    background-color: rgb(247,247,247);
                }

                .menu-drawer .linkset>li>a:focus {
                    color: #00A3E0;
                }

                .menu-drawer .linkset>li>a:active {
                    color: #333333;
                    background-color: rgb(252,252,252);
                }

                .menu-drawer .linkset >li > a.active {
                    color: #333333;
                    background-color: rgb(247,247,247);
                    color: #00A3E0;
                }

                .menu-drawer .linkset ul > li,
                .childlink__actions .add-to-quick-access,
                .childlink__actions .add {
                    border-color: rgb(245,245,245);
                }

                .menu-drawer .linkset > li.open > a,
                .menu-drawer .linkset ul > li.open > a {
                    background-color: rgb(247,247,247);
                }

                .menu-drawer .linkset > li.open > a:hover,
                .menu-drawer .linkset ul > li.open > a:hover {
                    background-color: rgb(242,242,242);
                }

                .menu-drawer .linkset > li.open > a:active,
                .menu-drawer .linkset ul > li.open > a:active {
                    background-color: rgb(250,250,250);
                }

                .menu-drawer .linkset ul li > a.active {
                    color: #00A3E0;
                }

                .menu-drawer .linkset ul li > a.active:hover {
                    background-color: rgb(247,247,247);
                }

                .menu-drawer .linkset ul li > a.active:active {
                    background-color: rgb(250,250,250);
                }

                .menu-drawer .linkset ul li > a {
                    color: rgba(51,51,51,0.8);
                }

                .menu-drawer .linkset ul li > a:hover {
                    color: #333333;
                    background-color: rgb(245,245,245);
                }

                .menu-drawer .linkset ul li > a:active {
                    color: #333333;
                    background-color: rgb(250,250,250);
                }

                .menu-drawer .linkset ul li > a:focus {
                    color: #333333;
                    color: #00A3E0;
                }

                .menu-drawer .linkset li .highlight {
                    color: #00A3E0;
                }

                .menu-drawer__filter-wrapper {
                    background: #FFFFFF;
                    border-bottom: 1px solid rgb(230,230,230);
                }

                .menu-drawer__collapse {
                    color: rgba(51,51,51,0.2);
                    border-left: 1px solid rgb(230,230,230);
                    background: none;
                }

                .menu-drawer__collapse:hover {
                    color: #00A3E0;
                    background-color: rgb(245,245,245);
                }

                .menu-drawer__collapse:active {
                    color: #00A3E0;
                    background-color: rgb(250,250,250);
                }

                .menu-drawer__menu-title {
                    color: #333333;
                    border-bottom: 1px solid rgb(230,230,230);
                }

                .childlink__actions .add,
                .childlink__actions .add-to-quick-access {
                    color: rgba(51,51,51,0.2);
                }

                .childlink__actions .add:hover,
                .childlink__actions .add-to-quick-access:hover {
                    background-color: rgb(245,245,245);
                }

                .childlink__actions .add:focus {
                    color: #00A3E0;
                }

                .childlink__actions .add:active,
                .childlink__actions .add-to-quick-access:active {
                    background-color: rgb(250,250,250);
                }

                .childlink__actions .add.active {
                    background-color: none;
                    color: #00A3E0;
                }

                .menu-drawer__add-card {
                    color: #333333;
                }

                .menu-drawer__add-card:hover,
                .menu-drawer__add-card:focus {
                    color: #00A3E0;
                    background-color: rgb(245,245,245);
                }

                .menu-drawer__add-card:active {
                    background-color: rgb(250,250,250);
                }

                .menu-drawer__add-card:hover .menu-drawer__add-icon {
                    color: #00A3E0;
                }

                .app-settings__tab-item:hover,
                .app-settings__tab-item--no-scroll:hover {
                    color: #00A3E0;
                }

                .app-settings__tab-item:active,
                .app-settings__tab-item--no-scroll:active {
                    background-color: rgb(252,252,252);
                }

                .app-settings__tab-item.active,
                .app-settings__tab-item--no-scroll.active {
                    background-color: rgb(250,250,250);
                    color: #00A3E0;
                }

                .app-settings__tab-item.active:active,
                .app-settings__tab-item--no-scroll.active:active {
                    background-color: rgb(245,245,245);
                }

                .number-callout {
                    background: #00A3E0;
                }

                /* Breadcrumbs
                --------------------------------------------------------------- */

                body.dashboard .breadcrumb.breadcrumb-cart li.active {
                    background: #00A3E0;
                    color: #ffffff;
                }

                body.dashboard .breadcrumb.breadcrumb-cart li.active:after {
                    border-color: transparent;
                    border-left-color: #00A3E0;
                    border-width: 20px;
                }

                /* Tooltip Popups
                --------------------------------------------------------------- */

        

                
    </style>
<script>
    // This function is needed for JS hooks.
    function getOriginalPageName() {
        return 'signin.asp';
    }

    function getUrlPath() {
        return '/signin.asp';
    }

    function getUrl() {
        return '/signin.asp?autopage=%2Fsitemap.asp';
    }

    function handleImageError(img, noImagePath){
        if(!noImagePath) {
            noImagePath = 'images/no-image.png';
        }
        if ($(img).attr('src') !== noImagePath) {
            $(img).attr('src', noImagePath);
        }    
    }
    var sitename = "coresite";
    var isWorkerDomain = false;
    var processPageTitle = isWorkerDomain && !false;
    var bValidIp = true;
    var sOfUrl   = 'https://coresite.cimproduction.com';
</script>
    <!-- Google Tag Manager -->
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','GTM-N4SKHRM');</script>
    <!-- End Google Tag Manager -->
    <script>
        window.dataLayer = window.dataLayer || [];
    </script> 

<script>
	var utils = {};

    utils.getParameter = function (param, context) {
        var value;
        if(!context) context = window;
        var parameters = context.location.search.replace('?', '');

        if (parameters) {
            var pattern = new RegExp('\\b' + param + '=([^;&]+)', 'gi');
            value = parameters.split(pattern)[1];
        }

        return value || '';
    };

    utils.buildImagePath = function(image){
        if(image && image.indexOf("http") > -1){
            imageUrl = image.replace(/http:/i, 'https:');
        }else{
            image = image.replace(oConfig.storefrontUrl, oConfig.sessionData.cdnUrl).toLowerCase();
            if(!image){
                imageUrl = oConfig.noImagePath || oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/images/' + oConfig.defaultImage.replace(/^\/+/, '');
            }
            else if(image.indexOf("/") > -1){
                imageUrl = oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/' + image.replace(/^\/+/, '');
            }
            else{
                imageUrl = oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/images/' + image.replace(/^\/+/, '');
            }
        }
        return imageUrl + '?v=3868854232';
    };

    utils.pageUrl = location.href.replace(/.+\//, '');
    utils.loginUrl = 'security_logon.asp?autopage=' + encodeURIComponent(utils.pageUrl);

    utils.pageType = function(){
        var pageType = "";
        if(utils.pageUrl == '' && pageType == ''){
            pageType = 'home';
        }else if(pageType != ''){
            switch(pageType){
                case 'prodcat':
                case 'product':
                    pageType = 'catalog';
                    break;
                case 'page-section':
                case 'webpage':
                    pageType = 'content';
                    break;
                default:
                    pageType = 'other';
                    break;
            }
        }else{
            switch(getOriginalPageName()){
                case 'pc_product_detail.asp':
                case 'pc_combined_results.asp':
                    pageType = 'catalog';
                    break;
                case 'showcart.asp':
                case 'account.asp':
                    pageType = 'checkout';
                    break;
                default:
                    pageType = 'other';
                    break;

            }
        }
        return pageType;
    }

    utils.htmlEncode = function(value){
        return $('<textarea/>').text(value).html();
    }

    utils.htmlDecode = function(value){
        return $("<textarea/>").html(value).text();
    }
</script>
<script>
    var cimcloud = {
        helpers: {
            urlPath: getUrlPath,
            loginUrl: utils.loginUrl,
            pageType: utils.pageType,
            urlParameter: utils.getParameter,
            buildImagePath: utils.buildImagePath
        },
        session: {
            accountNumber: "",
            accountName: "",
            username: "",
            email: "",
            firstName: "",
            lastName: "",
            sitename: "coresite"
        }
    }
</script>


<script src="/js/bundles/coreTop.js?d475520198521fb619c1789647eb14367bdf8391" ></script>


<script src="/js/bundles/corePlugins.js?d475520198521fb619c1789647eb14367bdf8391" ></script>


<script src="/js/bundles/coreKO.js?d475520198521fb619c1789647eb14367bdf8391" ></script>


<script src="/js/bundles/coreVendors.js?d475520198521fb619c1789647eb14367bdf8391" ></script>
        <!-- Start Header Custom Code -->
        
        <!-- End Header Custom Code -->
</head>

<body 
    class="signin interior dashboard t-ui-phase-3 site-type-2 no-template loggedout    t-ui-phase-3 no-template interior loggedout site-type-2 -loading-dom -loading-window" 
    
	    data-bind="css: { 'modal-open': viewModels.detailSlideOut && viewModels.detailSlideOut().isOpen() }"
    
>
    

    	
<script>
var timerStart = Date.now();  
var lastElapsed = 0; 
var pageHitDate = new Date();
var pageLoad = {
    pageHitKey: 'D1131383CD534581B54BE75B4603E701',
	sessionId: 'D79FD399538C4F9E919FD94A412B0F0C',
	orderId: '',
	createDate: (pageHitDate.getMonth()+1) + "/"
                + pageHitDate.getDate() + "/" 
                + pageHitDate.getFullYear() + " "  
                + pageHitDate.getHours() + ":"  
                + pageHitDate.getMinutes() + ":" 
                + pageHitDate.getSeconds(),
    priorTimeFrom: '',
    priorTime: '',
    urlRoot: 'coresite.cimproduction.com',
    pageName: 'signin.asp',
    uri: window.location.href,
	querystring: 'autopage=%2Fsitemap.asp',
	logs: [],
    clientTime: 0,
    serverTime: 0,
	totalTime: 0,
    dbReadCount: 0,
    dbWriteCount: 0
}; 

function addTimer(s) {
	var elapsed = (Date.now()-timerStart); //KEEP milliseconds
	var log = {
        source: 3,
        stepWithinSource: pageLoad.logs.filter( function(obj) { obj.source === 3 }).length,
        nickname: s,
        stepTime: elapsed - lastElapsed,
        cumulativeTime: elapsed
	};
	pageLoad.logs.push(log);
	lastElapsed = elapsed;
}

function logPageLoad() {
    if(pageLoad.logs.length > 0) {
        //sum the server-side, object, & client-side times onto the header.
        var serverTime=0;
        var maxClientSide=0;
        var len = pageLoad.logs.length-1;
        $.each(pageLoad.logs,function(i,o){
            if(o.source==0) { //server-side`
                serverTime=serverTime+o.cumulativeTime;
                pageLoad.dbReadCount += o.dbReadCount;
                pageLoad.dbWriteCount += o.dbWriteCount;
            /*} else if(o.source==2) { //object.. but these times are actually included in the client-side time since it is an ajax call. Don't add it twice. */
            } else if(o.source==3 && o.cumulativeTime > maxClientSide) { // on the last client-side record
                maxClientSide=o.cumulativeTime;
            }
        });
        var pt = pageLoad.priorTime;
        if(pt != "" && !isNaN(pt)){
            pageLoad.priorTime = parseFloat(pt);           
        } else {
            pageLoad.priorTime = 0;
        }
        pageLoad.serverTime = serverTime;
        pageLoad.clientTime = maxClientSide
        pageLoad.totalTime = parseInt(serverTime + maxClientSide + pageLoad.priorTime); //trim decimals
        $.ajax({
            url: '/api/timers/paymentpage/D1131383CD534581B54BE75B4603E701',
            data: JSON.stringify(pageLoad),
            type: "POST",
            contentType: "application/json"
        });
        drawPageHitData();
        pageLoad.logs = []; //<-- this is cleared so that the page hit isn't logged more than once.. See containing IF block...
    }
}

function drawPageHitData() {
    
}

function toSecString(ms) {
    var s = (parseInt(ms*10)/10); //only keep 1 decimal
    s = parseInt(s) / 1000;

    return s + "sec(s)";
}

function addPageLoadData(data) {
    /*
    OO data is an object with 3 props: reads, writes, details[]
    */
    if(data.reads) {
        pageLoad.dbReadCount += data.reads;
    }
    if(data.writes) {
        pageLoad.dbWriteCount += data.writes;
    }
    if(data.details) {
        pageLoad.logs = pageLoad.logs.concat(data.details);
    } 
}

addTimer('master top');
</script>

        
        <div class="app-signin dash-landing u-card">
            
    <header class="private-mode__header">
        <a href="https://coresite.cimproduction.com" name="Logo link" class="private-mode__main-logo">
            <img src="https://d3ccrbl9fhkqmr.cloudfront.net/images/logo-placeholder-black.png?v=3868854232" alt="Logo">
        </a>
    </header>
    <div id="signedOutContent" class="private-mode">
                <div class="app-signin-form text-center">
                    

<script language="JavaScript">


	$(function() {
		addGlobalModalCompletionHandler($('.global-modal'), handleCreateLogin);
	});

	function handleCreateLogin(){
		console.log('modal done');
		toggleLoadingWidget(true);
		location.reload();
	}

	function CheckForm(form)
	{
		if (form.username.value == "")
		{
			alert("Please enter a username");
			return false;
		}

	

		if (form.password.value == "")
		{
			alert("Password can not be blank")
			return false;
		}
	 
		showLoadingpopup();
		
		return true;
	}

	
	if (jQuery) {
		jQuery(function() { try { document.getElementById('logonUsername').focus(); } catch (err){ } });
	} else {
		window.onload = function() {
			try { document.getElementById('logonUsername').focus(); } catch (err) { }
		}
	}
	

	function showLoadingpopup() {
			
				toggleLoadingWidget(true);
			
		}
		
		function HideLoading() {
			
				toggleLoadingWidget(false);
			
		}

</script>


	<div class="login_overlay" id="login_overlay_div" style="display:none;">
		<div class="login_overlay_bkg">&nbsp;</div>
		<div class="login_overlay_win">
			<p><img src="js/jquery/loadinganimation.gif" /></p>
			<p><strong>Please wait while we load your profile&hellip;</strong></p>
		</div>
	</div>
			<header class="page-header">
			<h1>Sign in to Your Account</h1>
			</header>
		<div id="logon_container" class="row-fluid">
				<div class="local span12">
	<div class="contact-login well well-large" style="">
		<form
			name="custacctlogin"
			class="custom-account-login"
			id="custacctlogin"
			class="contact-login__form"
			method="POST"
			action="/security_logonscript_sitefront.asp?action=logon&parent_c_id=&returnpage=signin%2Easp%3F&pageredir=%2Fsitemap%2Easp"
			onsubmit="return CheckForm(this);"
			autocapitalize="off"
			autocorrect="off" 
			
		>
			<div></div>

			<label for="logonUsername" class="login_title custom-account-login__label">Username</label>
			<div class="login_field custom-account-login__input-wrapper">
				<input type="text" name="username" autocorrect="off" autocapitalize="off" id="logonUsername" class="un" data-test="login_username" custom-account-login__input" value="" placeholder="" >
			</div>

			

				<label for="logonPassword" class="login_title custom-account-login__label">Password</label>
				<div class="login_field custom-account-login__input-wrapper">
					<input type="password" name="password" autocorrect="off" autocapitalize="off" id="logonPassword" class="pw" data-test="login_password" custom-account-login__input" value="" placeholder="">
				</div>

				<div class="login_btn_wrap custom-account-login__submit-wrapper">
								<button type="submit" class="btn btn-primary custom-account-login__submit" data-test="login_button">Sign In</button>
				</div>

				
				<div></div>
				<input type="hidden" name="logontype" value="customer">

		</form>
	</div>

	
		<div class="login-links" style="">
			<ul class="unstyled">
					<li class="login-links__request-username"> 
							<a id="request_username_link" class="login-links__request-username-link global-modal" href="request_username.asp" data-title="Forgot your username?" data-size="small">
								Forgot your username?
							</a> 
					</li>
					<li class="login-links__reset-password"> 
						<a id="pass_reset_link" class="login-links__reset-password-link global-modal" href="request_password_reset.asp" data-title="Reset your password" data-size="small">
							Reset your password
						</a> 
					</li>
					<li class="login-links__create-login"> 
							<a href="create_login_select_acct.asp" class="login-links__create-login-link global-modal" title="Create a User " data-size="small">Create a new contact for your account</a> 	
					</li>

			</ul>
		</div>
				</div>
		</div>

	<div class="pull-right" style="">
		
	</div>
		<div id="wsplogin">
			<div>
				<form id="security_page" 
							method="POST" 
							action="https://coresite.cimproduction.com/security_logonscript_sitefront.asp?source=validipproduction&login=1&pageredir=%2Fsitemap%2Easp"
							onsubmit="toggleLoadingWidget(true)"
							>
					<input type="hidden" name="username" id="validip_username" value="wsptest">
					<input type="submit" value="ValidIP: Login wsptest" class="btn">
				</form>
			</div>
		</div>
                </div>
            
        </div>

        
<div class="global-body-append">
    
		<a class="app-logo__validip-info btn btn-mini" href="#siteInfo" role="button" data-toggle="modal">
			&nbsp;&nbsp;<i class="fab fa-bitbucket"></i> coresite
		</a>
		
	

	<div id="siteInfo" class="modal hide fade" tabindex="-1"  aria-hidden="true">
		<header class="modal-header">
			<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
			<h3 id="leaveCheckoutLabel"><i class="icon-info-sign"></i> Site Information</h3>
		</header>
		<div class="modal-body app-logo__validip-body">
			
		
		<table border="0" cellpadding="0" cellspacing="0">
            <tr>
				<td class="pageInfoLabel">Core Version:</td>
				<td>No Core Repo Found</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">ServerName:</td>
				<td>WEBSERVER</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">SiteName:</td>
				<td>coresite</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">WS_ID:</td>
				<td>C6E845C68CD04E9CBED3EAA7F6E81B83</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">L_WS_ID:</td>
				<td>C6E845C68CD04E9CBED3EAA7F6E81B83</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">Customer Site:</td>
				<td>coresite</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">StoreFrontURL:</td>
				<td>https://coresite.cimproduction.com</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">OrderFrontURL:</td>
				<td>https://coresite.cimproduction.com</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">ALTERNATE_DB_NAME:</td>
				<td>coresite</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">ALTERNATE_DB_SERVER:</td>
				<td>moddb01\mod01</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">FileName:</td>
				<td>c:\inetpub\wwwroot\WebSite\signin.asp</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">Local Commit Hash:</td>
				<td>d475520198521fb619c1789647eb14367bdf8391</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">SCRIPT_NAME:</td>
				<td>/signin.asp</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">HTTP_X_ORIGINAL_URL:</td>
				<td></td>
			</tr>
			<tr>
				<td class="pageInfoLabel">getUrl():</td>
				<td>/signin.asp?autopage=%2Fsitemap.asp</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">getUrlPath():</td>
				<td>/signin.asp</td>
			</tr>
			<tr>
				<td class="pageInfoLabel">getPageName():</td>
				<td>signin.asp</td>
			</tr>
		</table>
		</div>
		<div class="modal-footer">
			<a class="app-logo__validip-link btn btn-danger" href="https://coresite.cimproduction.com/?action=logout"><i class="fas fa-power-off"></i> Sign Out</a>
			<a class="app-logo__validip-link btn" href="https://coresite.cimproduction.com/show_session_info.asp?key=D79FD399538C4F9E919FD94A412B0F0C"><i class="fas fa-code"></i> Session Info</a>
			<a class="app-logo__validip-link btn" href="https://k8info.cimcloud.com/api/kubernetes/production/coresite/" target="_blank"><i class="fab fa-docker"></i> K8 Info</a>
			<a id="toggleTimerBtn" class="app-logo__validip-link btn" onclick="toggleTimers()"><i class="fas fa-clock"></i> Toggle Timers</a>
			
				<a class="app-logo__validip-link btn" target="_blank" href="https://bitbucket.org/websitepipeline/coresite" target="_blank"><i class="fab fa-bitbucket"></i> Bitbucket Repo</a>
			
		</div>
	</div>
	
	<script>

	$('#demoToolsBtn').click(function() {
		$('.modal').modal('hide');
	});

	function toggleTimers() {
		$.ajax({url: "?toggle=timers&modal=1", 
				success: function(data){
					if(data == "ON") {
						$("#toggleTimerBtn").addClass("btn-danger");
					} else {
						$("#toggleTimerBtn").removeClass("btn-danger");
					}
					utils.popToastr('Success', 'Timers are now ' + data, { 'positionClass' : 'toast-bottom-right' });
				}
			});
	}
	</script>

<div class="gtm-tracking"> 
    <script type="text/javascript">
        window.dataLayer.push({
            'CIMpageName'           : 'signin.asp', 
            'CIMorderFrontURL'      : 'https://coresite.cimproduction.com', 
            'CIMcustomerUsername'   : '', 
            'CIMcustomerKey'        : '',
            'CIMaccountKey'         : '',
			'CIMaccountRefId'       : '',
            'CIMsessionIP'          : '10.1.10.1',
			'CIMsessionOrderKey'    : '7C743E237AD14B3F9C9E236A7665CEC7',
			'CIMsessionIP'          : '10.1.10.1', 
            'CIMisLoggedIn'         : 'False'
        }); 
    </script> 
</div><!-- .gtm-tracking --> 

<div class="ga-ecommerce-tracking">
    <!-- START Tracking/Analytics Code -->
    <!-- END Tracking/Analytics Code -->

</div><!--.ga-ecommerce-tracking --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="hide">
  <symbol id="icon-user-circle-o" viewBox="0 0 28 28">
    <path d="M14 0c7.734 0 14 6.266 14 14 0 7.688-6.234 14-14 14-7.75 0-14-6.297-14-14 0-7.734 6.266-14 14-14zM23.672 21.109c1.453-2 2.328-4.453 2.328-7.109 0-6.609-5.391-12-12-12s-12 5.391-12 12c0 2.656 0.875 5.109 2.328 7.109 0.562-2.797 1.922-5.109 4.781-5.109 1.266 1.234 2.984 2 4.891 2s3.625-0.766 4.891-2c2.859 0 4.219 2.312 4.781 5.109zM20 11c0-3.313-2.688-6-6-6s-6 2.688-6 6 2.688 6 6 6 6-2.688 6-6z"></path>
  </symbol>
  <symbol id="icon-address-card" viewBox="0 0 32 28">
    <path d="M16 17.672c0-2.422-0.594-5.109-3.063-5.109-0.766 0.438-1.797 1.188-2.938 1.188s-2.172-0.75-2.938-1.188c-2.469 0-3.063 2.688-3.063 5.109 0 1.359 0.891 2.328 2 2.328h8c1.109 0 2-0.969 2-2.328zM13.547 9.547c0-1.953-1.594-3.547-3.547-3.547s-3.547 1.594-3.547 3.547c0 1.969 1.594 3.547 3.547 3.547s3.547-1.578 3.547-3.547zM28 17.5v-1c0-0.281-0.219-0.5-0.5-0.5h-9c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h9c0.281 0 0.5-0.219 0.5-0.5zM28 13.438v-0.875c0-0.313-0.25-0.562-0.562-0.562h-8.875c-0.313 0-0.562 0.25-0.562 0.562v0.875c0 0.313 0.25 0.562 0.562 0.562h8.875c0.313 0 0.562-0.25 0.562-0.562zM28 9.5v-1c0-0.281-0.219-0.5-0.5-0.5h-9c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h9c0.281 0 0.5-0.219 0.5-0.5zM32 4.5v19c0 1.375-1.125 2.5-2.5 2.5h-5.5v-1.5c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1.5h-12v-1.5c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1.5h-5.5c-1.375 0-2.5-1.125-2.5-2.5v-19c0-1.375 1.125-2.5 2.5-2.5h27c1.375 0 2.5 1.125 2.5 2.5z"></path>
  </symbol>
  <symbol id="icon-building" viewBox="0 0 22 28">
    <path d="M21 0c0.547 0 1 0.453 1 1v26c0 0.547-0.453 1-1 1h-20c-0.547 0-1-0.453-1-1v-26c0-0.547 0.453-1 1-1h20zM8 4.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM8 8.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM8 12.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM8 16.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM6 21.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM6 17.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM6 13.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM6 9.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM6 5.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM14 25.5v-3c0-0.281-0.219-0.5-0.5-0.5h-5c-0.281 0-0.5 0.219-0.5 0.5v3c0 0.281 0.219 0.5 0.5 0.5h5c0.281 0 0.5-0.219 0.5-0.5zM14 17.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM14 13.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM14 9.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM14 5.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM18 21.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM18 17.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM18 13.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM18 9.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5zM18 5.5v-1c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5v1c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5z"></path>
  </symbol>
  <symbol id="icon-currency-dollar" viewBox="0 0 20 20">
    <path d="M10 20c-5.523 0-10-4.477-10-10s4.477-10 10-10v0c5.523 0 10 4.477 10 10s-4.477 10-10 10v0zM11 15h1c1.657 0 3-1.343 3-3s-1.343-3-3-3v0h-4.010c-0.552 0-1-0.448-1-1s0.448-1 1-1v0h6.010v-2h-3v-2h-2v2h-1c-1.657 0-3 1.343-3 3s1.343 3 3 3v0h4c0.552 0 1 0.448 1 1s-0.448 1-1 1v0h-6v2h3v2h2v-2z"></path>
  </symbol>
  <symbol id="icon-check-square" viewBox="0 0 24 28">
    <path d="M10.703 20.297l9.594-9.594c0.391-0.391 0.391-1.016 0-1.406l-1.594-1.594c-0.391-0.391-1.016-0.391-1.406 0l-7.297 7.297-3.297-3.297c-0.391-0.391-1.016-0.391-1.406 0l-1.594 1.594c-0.391 0.391-0.391 1.016 0 1.406l5.594 5.594c0.391 0.391 1.016 0.391 1.406 0zM24 6.5v15c0 2.484-2.016 4.5-4.5 4.5h-15c-2.484 0-4.5-2.016-4.5-4.5v-15c0-2.484 2.016-4.5 4.5-4.5h15c2.484 0 4.5 2.016 4.5 4.5z"></path>
  </symbol>
  <symbol id="icon-life-bouy" viewBox="0 0 28 28">
    <path d="M14 0c7.734 0 14 6.266 14 14s-6.266 14-14 14-14-6.266-14-14 6.266-14 14-14zM14 2c-2.031 0-3.953 0.516-5.641 1.406l3.031 3.031c0.828-0.281 1.703-0.438 2.609-0.438 0.922 0 1.781 0.156 2.609 0.438l3.031-3.031c-1.687-0.891-3.609-1.406-5.641-1.406zM3.406 19.641l3.031-3.031c-0.281-0.828-0.438-1.703-0.438-2.609 0-0.922 0.156-1.781 0.438-2.609l-3.031-3.031c-0.891 1.687-1.406 3.609-1.406 5.641s0.516 3.953 1.406 5.641zM14 26c2.031 0 3.953-0.516 5.641-1.406l-3.031-3.031c-0.828 0.281-1.687 0.438-2.609 0.438-0.906 0-1.781-0.156-2.609-0.438l-3.031 3.031c1.687 0.891 3.609 1.406 5.641 1.406zM14 20c3.313 0 6-2.688 6-6s-2.688-6-6-6-6 2.688-6 6 2.688 6 6 6zM21.562 16.609l3.031 3.031c0.891-1.687 1.406-3.609 1.406-5.641s-0.516-3.953-1.406-5.641l-3.031 3.031c0.281 0.828 0.438 1.703 0.438 2.609s-0.156 1.781-0.438 2.609z"></path>
  </symbol>
  <symbol id="icon-calendar-plus-o" viewBox="0 0 26 28">
    <path d="M24 4c1.094 0 2 0.906 2 2v20c0 1.094-0.906 2-2 2h-22c-1.094 0-2-0.906-2-2v-20c0-1.094 0.906-2 2-2h2v-1.5c0-1.375 1.125-2.5 2.5-2.5h1c1.375 0 2.5 1.125 2.5 2.5v1.5h6v-1.5c0-1.375 1.125-2.5 2.5-2.5h1c1.375 0 2.5 1.125 2.5 2.5v1.5h2zM18 2.5v4.5c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-4.5c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM6 2.5v4.5c0 0.281 0.219 0.5 0.5 0.5h1c0.281 0 0.5-0.219 0.5-0.5v-4.5c0-0.281-0.219-0.5-0.5-0.5h-1c-0.281 0-0.5 0.219-0.5 0.5zM24 26v-16h-22v16h22zM14 17h3.5c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-3.5v3.5c0 0.281-0.219 0.5-0.5 0.5h-1c-0.281 0-0.5-0.219-0.5-0.5v-3.5h-3.5c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h3.5v-3.5c0-0.281 0.219-0.5 0.5-0.5h1c0.281 0 0.5 0.219 0.5 0.5v3.5z"></path>
  </symbol>
  <symbol id="icon-sticky-note" viewBox="0 0 24 28">
    <path d="M16 19.5v6.5h-14.5c-0.828 0-1.5-0.672-1.5-1.5v-21c0-0.828 0.672-1.5 1.5-1.5h21c0.828 0 1.5 0.672 1.5 1.5v14.5h-6.5c-0.828 0-1.5 0.672-1.5 1.5zM18 20h5.953c-0.141 0.75-0.547 1.594-1.016 2.063l-2.875 2.875c-0.469 0.469-1.313 0.875-2.063 1.016v-5.953z"></path>
  </symbol>
  <symbol id="icon-document-add" viewBox="0 0 32 32">
    <path d="M21 25v-3h1v3h3v1h-3v3h-1v-3h-3v-1h3zM17.257 29v0 0c1.009 1.221 2.535 2 4.243 2 3.038 0 5.5-2.462 5.5-5.5 0-2.137-1.219-3.99-3-4.9v-11.6l-6-7h-10.997c-1.106 0-2.003 0.898-2.003 2.007v22.985c0 1.109 0.891 2.007 1.997 2.007h10.26zM16.6 28h-9.6c-0.545 0-1-0.446-1-0.995v-23.009c0-0.54 0.446-0.995 0.996-0.995h10.004v4.994c0 1.119 0.895 2.006 1.998 2.006h4.002v10.207c-0.477-0.135-0.98-0.207-1.5-0.207-3.038 0-5.5 2.462-5.5 5.5 0 0.9 0.216 1.75 0.6 2.5v0 0zM18 3.5l4.7 5.5h-3.703c-0.546 0-0.997-0.452-0.997-1.009v-4.491zM21.5 30v0c-2.485 0-4.5-2.015-4.5-4.5s2.015-4.5 4.5-4.5c2.485 0 4.5 2.015 4.5 4.5s-2.015 4.5-4.5 4.5z"></path>
  </symbol>
  <symbol id="icon-document-add1" viewBox="0 0 32 32">
    <path d="M21 25v-3h1v3h3v1h-3v3h-1v-3h-3v-1h3zM16.022 29h-9.024c-1.107 0-1.997-0.899-1.997-2.007v-22.985c0-1.109 0.899-2.007 2.009-2.007h9.991v6.002c0 1.111 0.898 1.998 2.006 1.998h4.994v9.498c-0.77-0.321-1.614-0.498-2.5-0.498-3.59 0-6.5 2.91-6.5 6.5 0 1.289 0.375 2.49 1.022 3.5v0 0zM18 2v5.997c0 0.554 0.451 1.003 0.991 1.003h5.009l-6-7zM21.5 31c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5c-3.038 0-5.5 2.462-5.5 5.5s2.462 5.5 5.5 5.5v0z"></path>
  </symbol>
</svg>    
</div>
		<div class="modal-backdrop" style="z-index: 104; display: none;" 
			data-bind="
				visible: viewModels.detailSlideOut && viewModels.detailSlideOut().isOpen(), 
				click: viewModels.detailSlideOut && viewModels.detailSlideOut().close
			"></div>

    <script>
        function showLoadingpopup() {
            toggleLoadingWidget(true);
        }

        function HideLoading() {
            toggleLoadingWidget(false);
        }
    </script>



<div id="appLoadingWidget" class="sk-three-bounce--full-screen app-loading hide">
    <div class="sk-three-bounce">
        <div class="sk-child sk-bounce1"></div>
        <div class="sk-child sk-bounce2"></div>
        <div class="sk-child sk-bounce3"></div>
    </div>
</div>
    <div class="dashboard-bot-scripts">
        <div class="global-scripts">
    <script>

        var jsConfig = {
            static_pages: {
                content_key: '',
                content_type: ''
            }
        }
        if(processPageTitle){
            //$('.page-header h1').html('&nbsp;').show();
            var originalPageTitle = $('.page-header h1').html();
            var originalSubmitText = $('.form-actions button').html();
            var pageTitleText = "";
            if(pageTitleText.trim() != ''){
                $('.page-header h1').html(pageTitleText);
                $('.form-actions button').html( 'Save ' + pageTitleText);
                if(isWorkerDomain) pageTitleText = sitename.toUpperCase() + ' - ' + pageTitleText;
                document.title = pageTitleText;
            }else if (originalPageTitle){
                pageTitleText = originalPageTitle;
                $('.form-actions button').html( 'Save ' + pageTitleText);
                if(isWorkerDomain) pageTitleText = sitename.toUpperCase() + ' - ' + pageTitleText;
                document.title = pageTitleText;                
            }
            $('.page-header h1').show();
            $('.form-actions button').show();
        }
    </script>

    <script src="../hooks/js_custom_functions.js?d475520"></script>
    <script src="js/vendor/stretchy.min.js?d475520" data-filter=".stretchy, .stretchy *"></script>
        <!-- Start Footer Custom Code -->
        
        <!-- End Footer Custom Code -->

    <noscript class="noscript">
        WARNING: You will not be able to place an order or use most features of this site with JavaScript disabled
    </noscript>
</div>


<script src="/js/bundles/coreBot.js?d475520198521fb619c1789647eb14367bdf8391" ></script>


<script src="/js/bundles/coreBotPlugins.js?d475520198521fb619c1789647eb14367bdf8391" ></script>
        <script src="js/dashboard.js?d475520"></script>
    </div>
    </div> <!-- END private-mode -->


    <!-- KO Templates -->
    
<div class="interaction-tracker-scripts">

	<script type="text/javascript">
		//setup the main data objects for bindings.
		//This should always run to prevent KO issues.
		var viewModels = viewModels || {};
		var Config = Config || {};

		viewModels.data = ko.observable({});
		viewModels.inbox = ko.observable({});
		Config.userAvatars = {};
	</script>

	
		<style>
			.attachment-list div {
				display: inline-block;
				margin: 0 1em;
			}
		</style>

		<script type="text/javascript">
			viewModels.activity = ko.observable();
			viewModels.errors = ko.observableArray([]);
			viewModels.activityWorkQueues = ko.observableArray([]);
			viewModels.activityTypes = ko.observableArray([]);
			viewModels.activityTags = ko.observableArray([]);
			viewModels.activityPriorities = ko.observableArray([]);
			viewModels.activityLifecycleStages = ko.observableArray([]);
			viewModels.activityCategories = ko.observableArray([]);
			viewModels.activityAssignees = ko.observableArray([]);
			viewModels.users = ko.observableArray([]);
			viewModels.accountUsers = ko.observableArray([]);
			viewModels.accountSelectorList = ko.observableArray([]);
			viewModels.isUsersLoaded = ko.observable(false);
			viewModels.calling = ko.observable('');
			viewModels.detailSlideOut = ko.observable(new DetailSlideOutViewModel());

			if(window['augmentViewModel']) {
				augmentViewModel(viewModels);
			}

			var customerName = " ";
			var customerUsername = "";
			var closeModalOnSubmit = false;
			var useInbox = false;

			var currentUser = {
				id: "",
				phoneNumber: "",
				mobilePhoneNumber: "",
				isInternalUser: false
			};

			var defaultActivityTypeId = "4" || 4; 
			var defaultActivityTemplate = 'crm.activity.detail';

			// This custom ko binding allows for two-way binding on HTML elements
			// with the contenteditable flag. It WILL NOT update the value of
			// the element unless the element has contenteditable="false"
			ko.bindingHandlers.editableHTML = {
				init: function(element, valueAccessor) {
					var $element = $(element);
					var initialValue = ko.utils.unwrapObservable(valueAccessor());
					$element.html(initialValue);
					$element.on('input', function() {
					observable = valueAccessor();
					observable($element.html());
					});
				},
				update: function (element, valueAccessor) {
					var value = ko.utils.unwrapObservable(valueAccessor());

					if (!element.isContentEditable) {
						element.innerHTML = value;
					}
				}
			};

			$(function() {
				//load default information.
				if(Config.contextKey){
					
						getDataFromApi();
					
				} else {
					viewModels.data(ko.mapping.fromJS({}, interactionMapping));
				}
				if(useInbox){
					setTimeout(loadInboxData, 30000);
				}
			});

			/**
			* Loads the bulk of the data from the api for the current entity.
			*/
			function getDataFromApi() {
				if(Config && Config.apiBaseUrl && Config.contextType && Config.contextKey && Config.sessionKey) {
					$.ajax({
						url: Config.apiBaseUrl + Config.contextType + '/' + Config.contextKey + '/WithDetails',
						crossDomain: true,
						method: 'GET',
						headers: { 'Authorization' : 'Bearer ' + Config.sessionKey},
						success: function(data){
							viewModels.data(ko.mapping.fromJS(data, interactionMapping));
						},
						error: function(data){
							console.log('Error loading data')
							viewModels.data(ko.mapping.fromJS({}, interactionMapping));
						}
					});
				}
			}

			/*
			* KO mapping objects
			*/
			var activityMapping = {
				create: function(options) {
					return new ActivityBasicViewModel(options.data);
				},
				key: function(item) {
					return ko.utils.unwrapObservable(item.id);
				}
			};

			var interactionMapping = {
				create: function(options) {
					var entity = new parentEntity(options.data);
					return entity;
				}
			};

			/**************************************************************************************************************
			* Main view model for the interation tracker.
			*/
			var parentEntity = function(data){
				var self = this;

				self.id = ko.observable();
				self.activities = ko.observableArray([]);
				self.activitiesTest = ko.observableArray([]);
				self.activityTypeFilter = ko.observable('');

				self.filterActivities = function(activityTypeId) {
					if (activityTypeId !== undefined) {
						self.activityTypeFilter(activityTypeId);
					}

					var query = {
						"sort": [
							[
								"dateModified",
								"desc"
							]
						],
						"filters": [
							{
								"field": "accountId",
								"filterType": "equals",
								"parameters": [
									self.id()
								]
							}
						],
						"start": 0,
						"rows": 10
					}

					if (self.activityTypeFilter()) {
						query.filters.push({
								"field": "activityType.id",
								"filterType": "equals",
								"parameters": [
									self.activityTypeFilter(),
									null
								]
							})
					}

					if(Config && Config.apiBaseUrl && Config.sessionKey) {
						$.ajax({
							url: Config.apiBaseUrl + 'activities/search?include=notes,createdBy,activityType,account,activityTags.tag',
							cache: false,
							type: 'POST',
							dataType: 'json',
							contentType: "application/json",
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							data: JSON.stringify(query),
							error: function() {
								// Do nothing for now
							},
							success: function(res) {
								var mappedActivities = ko.mapping.fromJS(res.data, activityMapping, self.activities);
							}
						});
					}
				}

				self.newActivity = {
					externalComment: ko.observable(''),
					internalComment: ko.observable(''),
					mentions: ko.observableArray([]),
					activityTags: ko.observableArray([]),
					activityType: ko.observable({ id: defaultActivityTypeId }),
					dateOfActivity: ko.observable(Utilities.formatDateTime()),
					cancelChanges: function() {
						self.newActivity.externalComment('');
						self.newActivity.internalComment('');
						self.newActivity.mentions([]);
						self.newActivity.attachmentGroup.id('');
						self.newActivity.attachmentGroup.attachments([]);
						self.newActivity.activityTags([]);
						self.newActivity.activityType({ id: defaultActivityTypeId });
						self.newActivity.memberUsers([]);
						self.newActivity.requiredMemberUsers([]);
						self.newActivity.showOptions(false);
						self.newActivity.category({});
						self.newActivity.workQueue({});
						self.newActivity.priority({});
						self.newActivity.lifecycleStage({});
						self.newActivity.description('');
						self.newActivity.topic('');
						self.newActivity.onBehalfOf({});
						self.newActivity.accountId(null);

						if (window['Stretchy']) {
							Stretchy.resizeAll();
						}
					},
					keyPressed: function(d, e) {
						if ((e.ctrlKey || e.metaKey) && (e.keyCode == 13 || e.keyCode == 10)) {
							self.newActivity.updateActivity(d);
						}
					},
					updateActivity: function(data) {
						self.createActivity(data);
					},
					relatedTo: ko.observableArray([{
							id: ko.observable(Config.contextKey),
							type: ko.observable(Config.contextType),
							name: Utilities.getTitle()
						}
					]),
					isEditing: ko.pureComputed(function() {
						return !!self.newActivity.externalComment();
					}),
					memberUsers: ko.observableArray([]),
					requiredMemberUsers: ko.observableArray([]),
					tags: ko.observableArray([]),
					availableMembers: ko.observableArray([]),
					attachmentGroup: {
						id: ko.observable(),
						attachments: ko.observableArray([])
					},
					showOptions: ko.observable(false),
					category: ko.observable(),
					workQueue: ko.observable(),
					priority: ko.observable(),
					lifecycleStage: ko.observable(),
					description: ko.observable(''),
					topic: ko.observable(''),
					onBehalfOf: ko.observable(),
					accountId: ko.observable(),
					submitTicketCallback: function(data) {},
					wasSubmitted: ko.observable(false),
					showTicketConfirmation: ko.observable(false)
				};

				self.newActivity.description.subscribe(function(oldValue) {
					if (oldValue == '') {
						self.newActivity.dateOfActivity(Utilities.formatDateTime(Date.now()));
						self.newActivity.requiredMemberUsers.push({ id: currentUser.id, name: customerName });
					}
				}, null, "beforeChange");

				self.newActivity.accountId.subscribe(function(newValue) {
					self.newActivity.onBehalfOf(undefined);
					Utilities.loadAccountUsers(newValue);
				});

				setupAttachmentGroup(self.newActivity, 'activities');

				//setTimeout(function() {
				//	loadAvailableMembers(Config.contextType || 'users', Config.contextKey || Config.customerKey, function(data) {
				//		self.newActivity.availableMembers(data);
				//	});
				//}, 1000);

				ko.mapping.fromJS(data.entity, { 'activities': activityMapping}, self);

				self.url = self.url || '';
				self.emailAddress = self.emailAddress || '';

				if (_.isFunction(self.activities) && self.activities()) {
					self.activities.sort(function(a,b) {
						if (b.dateModified() > a.dateModified()) return 1;
						if (b.dateModified() < a.dateModified()) return -1;
						return 0;
					});
				}

				viewModels.activityTypes(data.activityTypes);
				viewModels.activityTags(data.activityTags);

				self.createActivity = function(data, callback){

					newActivity = self.newActivity;

					postData = {
						"dateOfActivity" : newActivity.dateOfActivity(),
						"activityType" : newActivity.activityType(),
						"topic": newActivity.topic(),
						"description" : newActivity.description(),
						"members": newActivity.memberUsers().map(function (m) {
							return { user: { id: m } };
						}),
						"activityTags" : newActivity.tags().map(function(t) {
							return { tag : { id: t}}
						}),
						"category": newActivity.category(),
						"workQueue": newActivity.workQueue(),
						"assignedTo": newActivity.workQueue() && newActivity.workQueue().manager,
						"priority": newActivity.priority(),
						"lifecycleStage": newActivity.lifecycleStage(),
						"onBehalfOf": newActivity.onBehalfOf()
					};

					// Add a note if...
					if (newActivity.internalComment() || newActivity.externalComment() 
						|| newActivity.attachmentGroup.attachments().length > 0) {
						if (!newActivity.internalComment() && !newActivity.externalComment()) {
							sPluralAttachmentText = utils.plural('Attachment', newActivity.attachmentGroup.attachments().length);
							newActivity.externalComment('[' + sPluralAttachmentText + ' added]');
						}
						postData.notes = [
								{
									"ExternalText" : newActivity.externalComment(),
									"InternalText" : newActivity.internalComment(),
									"Mentions" : newActivity.mentions().map(function(m) {
										return { user: { id: m } };
									}),
									"AttachmentGroup" : {
										"Attachments" : ko.toJS(newActivity.attachmentGroup.attachments())
									}
								}
							];
					}

					// If the accountId was set on the newActivity, override the context and add the Activity directly to that Account
					var activityEntityType = 'accounts';
					var activityEntityId = Config.accountKey;
					if (Config.contextKey != '' && Config.contextType != ''){
						activityEntityType = Config.contextType;
						activityEntityId = Config.contextKey;
					}
					if (newActivity.accountId()) {
						activityEntityType = 'accounts';
						activityEntityId = newActivity.accountId();
					}

					jQuery.ajax({
						url: Config.apiBaseUrl + activityEntityType + '/' + activityEntityId + '/Activities',
						data: JSON.stringify(postData),
						cache: false,
						type: 'POST',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request) {
							if (typeof(callback) == "function") {
								callback(data);
							}
							else {
								var addedActivity = new ActivityViewModel(data);
								viewModels.data().activities.unshift(addedActivity);
							}
						},
						error: function(data) {
							alert('Error posting Activity');
						}
					});

					newActivity.cancelChanges();
				};

				self.addNote = function(data){
					var activity = data;
					newNote = data.newNote;
					activityId = data.id();

					// Since currently the only way to add attachments to an Activity is on
					// a Note, and Notes require either internal or external text, this
					// allows the User to add attachments without typing any Note text
					if (!newNote.internalComment() && !newNote.externalComment() 
						&& newNote.attachmentGroup.attachments().length > 0) {
							sPluralAttachmentText = utils.plural('Attachment', newNote.attachmentGroup.attachments().length);
							newNote.externalComment('[' + sPluralAttachmentText + ' added]');
					}

					postData = {
						"ExternalText" : newNote.externalComment(),
						"InternalText" : newNote.internalComment(),
						"Mentions" : newNote.mentions().map(function(m) {
									return { User: { id: m } };
						}),
						"AttachmentGroup" : {
							"Attachments" : ko.toJS(newNote.attachmentGroup.attachments())
						}
					};

					jQuery.ajax({
						url: Config.apiBaseUrl + 'activities/' + activityId + '/notes',
						data: JSON.stringify(postData),
						type: 'POST',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request){
							var note = ko.mapping.fromJS(data);
							setupAttachmentGroup(note, 'notes');
							activity.addAttachment(note.attachmentGroup.attachments());
							activity.notes.unshift(note);
							activity.initialize(activity);
							if (activity.onUpdate && typeof(activity.onUpdate) == 'function') {
								activity.onUpdate();
							}

						},
						error: function(data) {
								alert('Error posting Comment');
						}
					});

					newNote.externalComment('');
					newNote.internalComment('');
					newNote.mentions([]);
					newNote.attachmentGroup.id('');
					newNote.attachmentGroup.attachments([]);
				};


				self.getEntityTemplate = function(data){
					return 'crm.' + Config.contextType;
				};

				self.drawAddress = function(data){
					var addressText = '';

					if(data.addressLine1()){
							addressText += data.addressLine1();
					}
					if(data.addressLine2()){
							addressText += '<BR>' + data.addressLine2();
					}
					if(data.addressLine3()){
							addressText += '<BR>' + data.addressLine3();
					}
					if(data.city() || data.stateProvince() || data.postalCode()){
							addressText += '<BR>' + data.city() + ' ' + data.stateProvince() + ', ' + data.postalCode();
					}
					if(data.country()){
							addressText += '<BR>' + data.country();
					}

					return addressText;
				};
			};

			/**************************************************************************************************************
			* Basic view model for an Activity. This is used for a simple card view, and has only the properties and methods
			* needed to display a simple representation of an Activity.
			*/
			function ActivityBasicViewModel(data) {
				var activity = this;

				// ActivityBasic Properties ------------------------------------------------------------
				activity.topic = ko.observable('');
				activity.description = ko.observable('');
				activity.showTopic = ko.observable(false);

				ko.mapping.fromJS(data, {}, activity);

				// ActivityBasic Methods ----------------------------------------------------------------
				activity.view = function() {
						if(useInbox) {
							var inbox = viewModels.inbox();
							if(inbox.close) {
								inbox.close();
							}
						}

										loadAndViewActivity(activity.id(), function(){
						viewModels.data().filterActivities();
					});
				};

				activity.clearNotification = function() {
					if(Config && Config.apiBaseUrl && Config.sessionKey) {
						$.ajax({
							url: Config.apiBaseUrl + 'activities/inbox/' + activity.id() + '/clearNotify',
							crossDomain: true,
							type: 'POST',
							method: 'POST',
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							contentType: "application/json",
							success: function(data){
								var inbox = viewModels.inbox();
								inbox.activities.remove(activity);
								inbox.selectActivity(null);
							},
							error: function(data){
								console.log("error clearing notification");
							}
						});
					}
				};

				activity.updateShowTopic = function() {
					activity.showTopic(
						!!activity.topic() &&
						activity.topic().substr(0,100) != activity.description().substr(0,100)
					)
				}

				activity.topic.subscribe(activity.updateShowTopic);
				activity.description.subscribe(activity.updateShowTopic);
				activity.updateShowTopic();
			}


			/**************************************************************************************************************
			* Advanced view model for an Activity. This is used for a detail view, and has all of the properties and methods
			* needed to interact with and update an Activity. It inherits from ActivityBasicViewModel.
			*/
			function ActivityViewModel(data) {
				ActivityBasicViewModel.call(this, data);
				var activity = this;

				// Activity Properties ----------------------------------------------------------------
				activity.lifecycleStage = ko.observable({});
				activity.workQueue = ko.observable({});
				activity.priority = ko.observable({});
				activity.category = ko.observable({});
				activity.assignedTo = ko.observable({});
				activity.onBehalfOf = ko.observable({});
				activity.relatedTo = ko.observableArray([]);
				activity.memberUsers = ko.observableArray([]);
				activity.requiredMemberUsers = ko.observableArray([]);
				activity.tags = ko.observableArray([]);
				activity.availableMembers = ko.observableArray([]);
				activity.isEditing = ko.observable(false);
				activity.logSortOrder = ko.observable('');
				activity.changeLog = ko.observableArray([]);
				activity.combinedLog = ko.observableArray([]);
				activity.account = ko.observable();
				activity.accountId = ko.observable();

				// Activity Methods -----------------------------------------------------------------------------
				activity.addAttachment = function(attachments) {
					if (activity.attachmentGroup) {
						activity.attachmentGroup.attachments(_.union(activity.attachmentGroup.attachments(), attachments));
					}
				};

				activity.edit = function() {
					activity.isEditing(true);
				};

				activity.cancelChanges = function(data) {
					getActivityWithDetails(activity.id(), function(data) {
						activity.initialize(data.activity);
					});
					activity.isEditing(false);
				};

				activity.updateActivity = function(data, event, additionalPostData) {
					activity.isEditing(false);

					postData = {
						"dateOfActivity" : activity.dateOfActivity(),
						"activityType" : {
							id: activity.activityType.id(),
						},
						"activityTags" : activity.tags().map(function(t) {
							return { tag: { id: t } };
						}),
						"members": activity.getCombinedMembers(),
						"topic": activity.topic(),
						"description": activity.description()
					};

					if (!activity.account() && activity.accountId()) {
						postData["account"] = {
							id: activity.accountId()
						}
					}

					if (additionalPostData) {
						for (var attrname in additionalPostData) { 
							postData[attrname] = additionalPostData[attrname];
						}
					}

					jQuery.ajax({
						url: Config.apiBaseUrl + 'activities/' + activity.id(),
						data: JSON.stringify(postData),
						cache: false,
						type: 'PATCH',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request) {
							// Reinitialize the activity with the updated data
							activity.initialize(data);
							// Reset available Members and the Related To
							activity.availableMembers(undefined);
							activity.relatedTo(undefined);
							activity.loadRelatedData();
							// Call the onUpdate function if set
							if (activity.onUpdate && typeof(activity.onUpdate) == 'function') {
								activity.onUpdate();
							}

						},
						error: function(data) {
							alert('Error posting Activity');
						}
					});

				};

				activity.updateTicket = function() {
					var postData = {
						lifecycleStage: viewModels.activity().lifecycleStage(),
						priority: 		viewModels.activity().priority(),
						workQueue: 		viewModels.activity().workQueue(),
						category: 		viewModels.activity().category(),
						assignedTo: 	viewModels.activity().assignedTo() || { id: '' },
						onBehalfOf:		viewModels.activity().onBehalfOf()
					};
					viewModels.activity().updateActivity({},{},postData);
					viewModels.activity().isEditing(false);
				}

				activity.selectItemAdded = function() {
					debugger;
				};

				activity.activityTitle = function(){
					var sCreatedBy = activity.createdBy.fullName();
					var sAccountName = ''; // viewModels.data().name();

					if (_.isFunction(activity.activityType)) {
						return "Activty Type Not Set!!!";
					}

					var template = activity.activityType.defaultTopicTemplate();
					template = template.replace('{CreatedBy}', sCreatedBy);
					template = template.replace('{EntityName}', sAccountName);
					return template;
				};

				activity.resetMemberUsers = function() {
					var requiredIds = {}
					if (activity.assignedTo() && activity.assignedTo().id) {
						requiredIds[activity.assignedTo().id] = true;
					}
					if (activity.createdBy && activity.createdBy.id()) {
						requiredIds[activity.createdBy.id()] = true;
					}
					if (activity.onBehalfOf() && activity.onBehalfOf().id) {
						requiredIds[activity.onBehalfOf().id] = true;
					}
					// memberUsers = all members *except* the assignedTo, createdBy, and onBehalfOf
					activity.memberUsers(
						activity.members()
						.filter(function(m) {
							var userId = ko.utils.unwrapObservable(m.user.id);
							return !requiredIds[userId];
						})
						.map(function (m) {
							return ko.utils.unwrapObservable(m.user.id);
						})
					);
					// requiredMemberUsers = *only* the assignedTo, createdBy, and onBehalfOf
					activity.requiredMemberUsers(
						activity.members()
						.filter(function(m) {
							var userId = ko.utils.unwrapObservable(m.user.id);
							return requiredIds[userId];
						})
						.map(function (m) {
							return {
								id: ko.utils.unwrapObservable(m.user.id),
								name: ko.utils.unwrapObservable(m.user.fullName())
							};
						})
					);
				};

				activity.getCombinedMembers = function() {
					var requiredMemberIds = activity.requiredMemberUsers().map(function(m) {
						return m.id;
					});
					var memberIds = _.uniq(_.union(activity.memberUsers(), requiredMemberIds));
					
					return memberIds.map(function (m) {
						return { user: { id: m } };
					});
				}

				activity.loadRelatedData = function(callback) {

					var request1;
					var request2;
					var request3;

					//we will preload the members list with the current members of the activity.
					//this will prevent the member selection from appearing after the ajax call.
					var availableMembers = ko.utils.unwrapObservable(activity.availableMembers);
					if (!availableMembers || !availableMembers.length) {
						//get all current members to add them to the list of available members.
						var members = ko.mapping.toJS(activity.members).map(function (m) {return m.user});
						activity.availableMembers(members);

						//this has to be called after availableMembers loads because they are not in the selection yet.
						activity.resetMemberUsers();
					}

					var relatedTo = ko.utils.unwrapObservable(activity.relatedTo);
					if (!relatedTo || !relatedTo.length) {

						request1 = jQuery.ajax({
							url: Config.apiBaseUrl + 'activities/' + activity.id() + '/relatedTo',
							cache: false,
							type: 'GET',
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							dataType: 'json',
							contentType: "application/json",
							success: function(data,status,request) {
								ko.mapping.fromJS(data, {}, activity.relatedTo);

								for (var i in data) {
									var relatedTo = data[i];
									loadAvailableMembers(relatedTo.type, relatedTo.id, function(data) {

										//get all current members to add them to the list of available members.
										var members = ko.mapping.toJS(activity.availableMembers);

										//merge the two lists and removed duplicates based on their ids.
										activity.availableMembers(_.uniq(_.union(data, members), false, 'id'));
										activity.newNote.availableMembers(activity.availableMembers());

										//this has to be called after availableMembers is set or it will clear the selection list.
										activity.resetMemberUsers();
									});
								}
							},
							error: function(data) {
									console.log('Error getting related to');
							}
						});
					}

					var activityTypes = ko.utils.unwrapObservable(viewModels.activityTypes);
					if (!activityTypes || !activityTypes.length) {
						request2 = jQuery.ajax({
							url: Config.apiBaseUrl + 'activityTypes',
							cache: false,
							type: 'GET',
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							dataType: 'json',
							contentType: "application/json",
							success: function(data,status,request) {
									ko.mapping.fromJS(data, {}, viewModels.activityTypes);
							},
							error: function(data) {
									console.log('Error getting activity types');
							}
						});
					}

					var activityTags = ko.utils.unwrapObservable(viewModels.activityTags);
					if(!activityTags || !activityTags.length) {
						request3 = jQuery.ajax({
							url: Config.apiBaseUrl + 'activityTags',
							cache: false,
							type: 'GET',
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							dataType: 'json',
							contentType: "application/json",
							success: function(data,status,request) {
									viewModels.activityTags(data);
									activity.tags(ko.mapping.toJS(activity.activityTags).map(function (m) {return ko.utils.unwrapObservable(m.tag.id);}));
							},
							error: function(data) {
									console.log('Error getting activity tags');
							}
						});
					}

					if (callback) {
						$.when(request1, request2, request3).done(callback);
					}

				};

				activity.loadAccountUsers = function (callback) {
					callback = callback || function() {};

					if (activity.account() && activity.account().id) {
						Utilities.loadAccountUsers(activity.account().id(), callback);
					}
				}

				activity.sortLog = function(sortOrder) {
					if (activity.combinedLog()) {
						activity.combinedLog.sort(function(a,b) {
							var sortArray = [a, b];
							if (sortOrder == "desc") sortArray.reverse();
							if (sortArray[0].dateCreated() > sortArray[1].dateCreated()) return 1;
							if (sortArray[0].dateCreated() < sortArray[1].dateCreated()) return -1;
							return 0;
						});
					}
					activity.logSortOrder(sortOrder || "asc");
				};

				activity.initialize = function(data) {
					ko.mapping.fromJS(data, {}, activity);
					setupAttachmentGroup(activity, 'activities');
					activity.attachmentGroup.id(activity.id());
					activity.combinedLog([]);
					if (activity.notes()) {
						activity.notes().forEach(function(note){
							setupAttachmentGroup(note, 'notes');
							activity.addAttachment(note.attachmentGroup.attachments());
							activity.combinedLog.push(note);
						});
					}
					if (activity.changeLog()) {
						activity.changeLog().forEach(function(entry){
							if (entry.fromData && entry.fromData() && typeof(entry.fromData()) != 'object')  {
								entry.fromData(JSON.parse(entry.fromData()));
								entry.toData(JSON.parse(entry.toData()));
								entry.propertyChanged = {};
								for (prop in entry.fromData()) {
									var fromProp = entry.fromData()[prop];
									var toProp = entry.toData()[prop];
									entry.propertyChanged[prop] = 
										!((!fromProp && !toProp) || (fromProp && toProp && fromProp.id == toProp.id));
								}
							}
							activity.combinedLog.push(entry);
						});
					}
					activity.sortLog("desc");
					activity.dateOfActivity(Utilities.formatDateTime(activity.dateOfActivity()));
					activity.lastNote = activity.notes()[activity.notes().length - 1];
					activity.tags(ko.mapping.toJS(activity.activityTags).map(function (m) {return ko.utils.unwrapObservable(m.tag.id);}));
					activity.originalData = data;
					if (activity.activityType && activity.activityType.defaultDetailTemplate()) {
						activity.primaryTemplate = activity.activityType.defaultDetailTemplate();
					} else {
						activity.primaryTemplate = defaultActivityTemplate;
					};
					// Setup selectables (sets an object on Activity to the matching one from the list of available options)
					Utilities.setupSelectable(activity.priority, viewModels.activityPriorities);
					Utilities.setupSelectable(activity.workQueue, viewModels.activityWorkQueues);
					Utilities.setupSelectable(activity.lifecycleStage, viewModels.activityLifecycleStages);
					Utilities.setupSelectable(activity.category, viewModels.activityCategories);
					Utilities.setupSelectable(activity.assignedTo, viewModels.activityAssignees);
					activity.loadAccountUsers(function(){
						Utilities.setupSelectable(activity.onBehalfOf, viewModels.accountUsers);
					});
				};


				// Initialize Activity ----------------------------------------------------------------

				// Initialize function allows for re-initializing an Activity			
				activity.initialize(data);
				
				activity.newNote = {
					externalComment: ko.observable(''),
					internalComment: ko.observable(''),
					mentions: ko.observableArray([]),
					availableMembers: ko.observableArray([]),
					showOptions: ko.observable(false),
					isValid: ko.observable(false),
					buttonText: ko.observable(''),
					keyPressed: function(d, e) {
						if ((e.ctrlKey || e.metaKey) && (e.keyCode == 13 || e.keyCode == 10)) {
							viewModels.data().addNote(activity);
						}
					}
				};

				activity.newNote.internalComment.subscribe(function(comment){
					var availableMembers = ko.utils.unwrapObservable(activity.newNote.availableMembers);
					if (comment.length == 1 && (!availableMembers || !availableMembers.length)) {
						activity.loadRelatedData();
					}
				});

				setupAttachmentGroup(activity.newNote, 'notes');

				// All of the subscribe functions below are because Knockout's computed properties
				// SUCK and are unreliable. Bring on Vue JS!!! (Steven H - 1/31/2018)

				activity.isEditing.subscribe( function(newValue) {
					if (newValue) {
						activity.loadRelatedData();
					}
				});
				
				activity.checkForValidNote = function(){
					var isValid = false;
					var buttonText = "Reply" + (currentUser.isInternalUser ? ", Note," : "") + " or Attachment Required";
					var attachmentMsg = '';
					var internalMsg = '';
					var externalMsg = '';
					if (activity.newNote.attachmentGroup.attachments().length > 0) {
						attachmentMsg = "Add Attachment";
						isValid = true;
					}
					if (activity.newNote.internalComment()) {
						internalMsg = "Add Note";
						isValid = true;
					}
					if (activity.newNote.externalComment()) {
						externalMsg = "Send Reply";
						isValid = true;
					}
					buttonText = (externalMsg + (externalMsg && internalMsg ? ' and ' : '') + internalMsg)
									|| attachmentMsg || buttonText;

					activity.newNote.isValid(isValid);
					activity.newNote.buttonText(buttonText);
				};

				activity.newNote.internalComment.subscribe(activity.checkForValidNote);
				activity.newNote.externalComment.subscribe(activity.checkForValidNote);
				activity.newNote.attachmentGroup.attachments.subscribe(activity.checkForValidNote);
				activity.checkForValidNote();

			}

			ActivityViewModel.prototype = Object.create(ActivityBasicViewModel.prototype);
			ActivityViewModel.prototype.constructor = ActivityViewModel;

			/**************************************************************************************************************
			* View model for the Detail Slide Out. This works like a modal, and can be loaded with any Knockout template.
			*/
			function DetailSlideOutViewModel() {
				var detailSO = this;

				detailSO.defaultTemplate = 'crm.no.template';
				detailSO.isOpen = ko.observable(false);
				detailSO.sidebarOpen = ko.observable(false);
				detailSO.templateName = ko.observable(detailSO.defaultTemplate);
				detailSO.data = ko.observable({});
				detailSO.wasUpdated = ko.observable(false);
				detailSO.onClose = undefined;

				detailSO.close = function() {
					detailSO.isOpen(false);
					if (detailSO.onClose && typeof(detailSO.onClose) == 'function') {
						detailSO.onClose(detailSO.wasUpdated());
					}
				};

				detailSO.open = function() {
					detailSO.isOpen(true);
				}

				detailSO.toggleSidebar = function() {
					detailSO.sidebarOpen(!detailSO.sidebarOpen());
				}

			}

			/**************************************************************************************************************
			* Utility function to configure the attachment group on an entity. It sets everything to be used with 
			* the attachment upload binding handler.
			*/
			function setupAttachmentGroup(entity, entityName) {
				if (!entity.attachmentGroup || _.isFunction(entity.attachmentGroup)) {
					entity.attachmentGroup = {
						id: ko.observable(),
						attachments: ko.observableArray()
					};
				}

				entity.attachmentGroup.entityName = entityName

				entity.attachmentGroup.removeAttachment = function(data) {
					var attachmentIndex = _.findIndex(entity.attachmentGroup.attachments(), function(attachment) {
						return attachment.name() == data.model.name() && attachment.location() == data.model.location();
					});
					if(attachmentIndex != -1) {entity.attachmentGroup.attachments.splice(attachmentIndex, 1);}
				}

				entity.attachmentGroup.add = function() {
					modal.open({
						body: '<div id="modalTemplate" data-bind="template: \'crm.attachments.addModal\'"></div>',
						title: 'Attach Files',
						size: 'small',
						backdrop: 'static', 
						footer: '<button class="btn btn-primary" onClick="modal.done();">Done</button>'
					});
					setTimeout(function() {
						var modalTemplate = $('#modalTemplate');
						ko.applyBindings(entity, modalTemplate[0]);

						modalTemplate.focus();
					}, 10);
				}
			}

			/**
			* Utility function to load the members that can be added to an activity.
			* @param {string} entity The name of the entity to load.
			* @param {string} key The Id of the entity to load.
			* @callback callback The function to call and pass the loaded data.
			*/
			function loadAvailableMembers(entity, key, callback) {
				callback = callback || function() {};

				if(Config && Config.apiBaseUrl && Config.sessionKey && entity && key) {
					jQuery.ajax({
						url: Config.apiBaseUrl + entity + '/' + key + '/availableMembers',
						cache: true,
						type: 'GET',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request) {
							callback(data);
						},
						error: function(data) {
							console.log('Error getting availableMembers');
						}
					});
				}
			}

			/**************************************************************************************************************
			* Utility function to view an Activity in the Detail Slide Out.
			* @param {ActivityViewModel} activityVM The ActivityViewModel to view. It should already be loaded with data.
			*/
			function setupActivityToView(activityVM) {
				viewModels.activity = viewModels.activity || ko.observable();
				viewModels.activity(activityVM);
				viewModels.activity().loadRelatedData();
			};

			/**************************************************************************************************************
			* Utility function to view an Activity in the Detail Slide Out.
			* @param {ActivityViewModel} activityVM The ActivityViewModel to view. It should already be loaded with data.
			*/
			function viewActivity(activityVM, onClose) {
				viewModels.detailSlideOut().templateName(viewModels.detailSlideOut().defaultTemplate);
				viewModels.detailSlideOut().data({});
				viewModels.detailSlideOut().wasUpdated(false);

				setupActivityToView(activityVM);
				viewModels.activity().onUpdate = function(){
					viewModels.detailSlideOut().wasUpdated(true);
				};

				viewModels.detailSlideOut().data(viewModels.activity);
				viewModels.detailSlideOut().templateName(viewModels.activity().primaryTemplate);
				viewModels.detailSlideOut().onClose = onClose|| function() {
					viewModels.activity().cancelChanges();
				};
				viewModels.detailSlideOut().open();
			};

			/**************************************************************************************************************
			* Utility function to load an Activity from the API with all of its supporting lists.
			* @param {int} activityId The id of the Activity to view.
			* @param {function} callback The callback function 
			*/
			function getActivityWithDetails(activityId, callback) {
				callback = callback || function() {};

				if(Config && Config.apiBaseUrl && Config.sessionKey) {
					$.ajax({
						url: Config.apiBaseUrl + 'activities/' + activityId + '/withDetails',
						crossDomain: true,
						method: 'GET',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						contentType: "application/json",
						success: function(data){
							var assignees = _.filter(data.activityAssignees, function(assignee){
								return !assignee.username.includes('@cimcloud.com');
							});
							viewModels.activityTypes(data.activityTypes);
							viewModels.activityTags(data.activityTags);
							viewModels.activityWorkQueues(data.workQueues);
							viewModels.activityPriorities(data.activityPriorities);
							viewModels.activityLifecycleStages(data.activityLifecycleStages);
							viewModels.activityCategories(data.activityCategories);
							viewModels.activityAssignees(assignees.sort(function(a,b) {
								return a.firstName < b.firstName ?  -1 : 1;
							}));
							callback(data);
						},
						error: Utilities.ajaxError
					});
				}
			};

			/**************************************************************************************************************
			* Utility function to load an Activity by Id and then view it in the Detail Slide Out.
			* @param {int} activityId The Id of the Activity to view. An AJAX call will get the data for it.
			*/
			function loadAndViewActivity(activityId, onClose) {
				getActivityWithDetails(activityId, function(data) {
					viewActivity(new ActivityViewModel(data.activity), onClose);
				});		
			};
			
			/**************************************************************************************************************
			* Additional utility functions.
			*/
			if (!window['Utilities']) {
				Utilities = {};
			}
			Utilities.formatDateTime = function(dateTime) {
				if (window['moment']) {
					// moment initialization with string is being deprecated, so...
					var dt = new Date(dateTime);
					return moment(dt).format('M/DD/YYYY h:mm A')
				}
			};
			Utilities.getIconFromEntityType = function(type) {
				switch(type) {
					case 'Account':
					case 'accounts':
						return 'icon-building';
					case 'User':
					case 'users':
						return 'icon-user';
					case 'Order':
					case 'orders':
						return 'icon-shopping-cart';
					case 'Invoice':
					case 'inoices':
						return 'icon-file-text';
				}
			};
			Utilities.getTitle = function() {
				return ko.pureComputed(function() {
					if (viewModels.data() && viewModels.data().id) {
						switch(Config.contextType) {
							case 'Account':
							case 'accounts':
								return viewModels.data().name() + ' (' + viewModels.data().referenceId() + ')';
							case 'User':
							case 'users':
								return viewModels.data().fullName();
							case 'Order':
							case 'orders':
								return viewModels.data().orderNumber();
							case 'Invoice':
							case 'inoices':
								return viewModels.data().invoiceNumber();
						}
					}
					return '';
				});
			};

			Utilities.userInitials = function(person){
				var initials = '?';
				if(person && person.firstName && person.lastName){
					initials = person.firstName().substr(0,1).toUpperCase() + person.lastName().substr(0,1).toUpperCase();
				}
				return initials;
			};

			Utilities.userFullName = function(person){
				var fullname = 'Unknown User';
				if(person.firstName && person.lastName){
					fullname = person.firstName() + ' ' + person.lastName();
				}
				return fullname;
			};

			Utilities.userAvatar = function(person){
				if(!person || !person.id) return '';
				var personId = ko.utils.unwrapObservable(person.id);

				//added "seed" property so the colors are consistent per user.

				if(Config.userAvatars[personId]){
					return Config.userAvatars[personId].color;
				}else{
					var colorHex = randomColor({ 
						hue: 'random',
						seed: person.fullName(),
						luminosity: 'dark' // dark, light, bright
					});
					Config.userAvatars[personId] = {color: colorHex};
					return colorHex;
				}
			};

			Utilities.setupSelectable = function(observableItem, observableList) {
				if (observableItem && observableItem() && observableList && observableList()) {
					var item = ko.mapping.toJS(observableItem());
					var obj = _.find(observableList(), function (obj) { return obj.id === item.id; });
					if (obj) {
						observableItem(obj);
					}
					else {
						observableList.push(item);
						observableItem(item);
					}
				}
			}

			Utilities.searchAccounts = function(query, callback) {
				callback = callback || function() {};

				if (!(query.length && query.length > 0)) return callback();
				if(Config && Config.apiBaseUrl && Config.sessionKey) {
					$.ajax({
						url: Config.apiBaseUrl + 'accounts/search',
						cache: false,
						type: 'POST',
						dataType: 'json',
						contentType: "application/json",
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						data: JSON.stringify({
							fields: [
								{
									name: "number"
								},
								{
									name: "name"
								}
							],
							sort: [
								[
									"name",
									"asc"
								]
							],
							filters: [],
							start: 0,
							rows: 25,
							fullTextSearch: {
								searchPhrase: query,
								suggestedFields: [
									"number",
									"name"
								]
							}
						}),
						error: function() {
							callback();
						},
						success: function(res) {
							callback(res.data);
						}
					});
				} else {
					return callback();
				}
			}

			Utilities.loadAccountUsers = function (accountId, callback) {
				callback = callback || function() {};

				if (accountId && Config && Config.apiBaseUrl && Config.sessionKey) {
					jQuery.ajax({
						url: Config.apiBaseUrl + 'accounts/' + accountId + '/users',
						cache: true,
						type: 'GET',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request) {
							viewModels.accountUsers(data);
							callback(data);
						},
						error: function(data) {
							console.log('Error getting Activity Account Users');
						}
					});
				}
			}

			/**************************************************************************************************************
			* Inbox
			*/

			//KO Mapping object.
			var inboxMapping = {
				create: function(options) {
					return new InboxViewModel(options.data);
				}
			};

			function loadInboxData() {
				if(Config && Config.apiBaseUrl && Config.sessionKey) {
					$.ajax({
						url: Config.apiBaseUrl + 'activities/inbox',
						crossDomain: true,
						method: 'GET',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						contentType: "application/json",
						success: function(data){
							if (viewModels.inbox().selectedActivity) {
								ko.mapping.fromJS(data, inboxMapping, viewModels.inbox);
							} else {
								viewModels.inbox(ko.mapping.fromJS(data, inboxMapping));
							}
						},
						error: function(data){
							ko.mapping.fromJS({}, inboxMapping, viewModels.inbox);
						}
					});
				}
				// auto refresh after 30 seconds.
				setTimeout(loadInboxData, 30000);
			}

			/**************************************************************************************************************
			* View Model for the Inbox.
			*/
			function InboxViewModel(data) {
				var self = this;

				self.activities = ko.observableArray([]);
				self.selectedActivity = ko.observable();

				ko.mapping.fromJS(data, { 'activities': activityMapping}, self);

				self.selectActivity = function(activity) {
					self.selectedActivity(activity);
				}

				self.open = function() {
					$('html').addClass('drawer-open');
				};

				self.close = function() {
					$('html').removeClass('drawer-open');
				};

				self.headerClick = function() {
					$('html').toggleClass('drawer-open');
				}

				$(document).on('click', function(e) {
					if ($(e.target).closest('.drawer').length === 0) {
						viewModels.inbox().close();
					}
				});
			}

			/**************************************************************************************************************
			* More utility functions
			*/
			function dial(entity, key, description) {
				return function () {
					console.log('Dialing...');
					var callFrom = $('#callFrom').val();
					viewModels.calling(description);

					if(Config && Config.apiBaseUrl && Config.sessionKey) {
						$.ajax({
							url: Config.apiBaseUrl + entity + '/' + key + '/call',
							cache: false,
							type: 'POST',
							headers: {
								'Authorization' : 'Bearer ' + Config.sessionKey
							},
							contentType: "application/json",
							data: JSON.stringify({
								from: callFrom
							}),
							success: function(data,status,request){
								setTimeout(function() {
									$('#modalCalling').modal('hide');
								}, 5000)
							},
							error: function(data) {
								$('#modalCalling').modal('hide');
								alert('Could not start call');
							}
						});
					} else {
						$('#modalCalling').modal('hide');
						alert('Could not start call');
					}
				}
			}

			$(function () {
				$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
					var target = $(e.target).attr("href") // activated tab
					if(Config && Config.apiBaseUrl && Config.contextType && Config.contextKey) {
						if (target ==='#makeCallTab' && !viewModels.isUsersLoaded()) {
							if(Config && Config.apiBaseUrl && Config.contextType && Config.contextKey && Config.sessionKey) {
								$.ajax({
									url: Config.apiBaseUrl + Config.contextType + '/' + Config.contextKey + '/users',
									type: 'GET',
									headers: {
										'Authorization' : 'Bearer ' + Config.sessionKey
									},
									dataType: 'json',
									contentType: "application/json",
									success: function(data,status,request){
										ko.mapping.fromJS(data, {}, viewModels.users);
										viewModels.isUsersLoaded(true);
									},
									error: function(data) {

									}
								});
							}
						}
					}
				});
			});

			//http://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
			function isMobile() {
				var check = false;
				(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
				return check;
			};

		</script>

		<!-- Draw the Interaction (Activity) Tracker ****************************************************************** -->
		


		<script>
			//*************************************************************************************************************
			//knockout binding hander for attachments. Internally it uses dropzone.
			//This can technically support attachments for any entity that has an attachmentGroup.
			ko.bindingHandlers.attachmentUpload = {
				defaultOptions: {
					url: '#',
					method: 'post',
					parallelUploads: 2,
					maxFilesize: 10,
					paramName: 'file',
					uploadMultiple: false,
					acceptedFiles: '.jpg, .jpeg, .png, .bmp, .gif, .doc, .docx, .xls, .xlsx, .csv, .txt, .zip, .pdf, .msg',
					accept: function(file, done) {
						if (file) {
							if (!file.type) {
								var ext = file.name.split('.').pop();
								if (ext === 'msg') {
									Object.defineProperty(file, 'type', { value: 'application/vnd.ms-outlook' });
								}
							}
							done();
						}
					},
					entity: 'activities',
					addRemoveLinks: true,
					dictDefaultMessage: '<p><i class=icon-paperclip></i> <b>Add file(s)</b>, or drop them here to upload.</p>' + 
															'<p class="text-small">' +
																'Supported File Types: <br>' +
																'.jpg, .jpeg, .png, .bmp, .gif, .doc, .docx, .xls, .xlsx, .csv, .txt, .zip, .pdf, .msg' +
															'</p>',
					dictFileTooBig: 'File is too big ({{filesize}} MB). Max file size is {{maxFilesize}} MB.',
					error: function(message) {
						Utilities.ajaxError("Attachment Error", message)();
					}
				},
				init: function(element, valueAccessor, allBindings, viewModels, bindingContext) {

					Dropzone.autoDiscover = false;

					var options = valueAccessor();
					var entity = options.value;

					$.extend(options, ko.bindingHandlers.attachmentUpload.defaultOptions);

					if (options.init) {
						options.__init = options.init;
					}

					options.init = function() {
						var dz = this;
						var formPostData = {};

						if(Config && Config.apiBaseUrl && Config.sessionKey) {
							jQuery.ajax({
								url: Config.apiBaseUrl + 'attachments/FormPostData',
								cache: false,
								type: 'GET',
								headers: {
									'Authorization' : 'Bearer ' + Config.sessionKey
								},
								dataType: 'json',
								contentType: "application/json",
								success: function(data,status,request) {
									formPostData = data;
									dz.options.url = data.uploadUrl;
								},
								error: function(data) {
									options.error('Error getting permission to upload attachments.');
								}
							});
						} else {
							options.error('Error getting permission to upload attachments (missing Config values).');
						}

						this.on('sending', function(file, xhr, formData) {
							for (var key in formPostData.uploadData) {
								var value = formPostData.uploadData[key];

								formData.append(key, value);
							}
						});
						this.on('success', function (file, resp) {
							var attachment = {
								name: file.name,
								fileName: file.name,
								type: file.type,
								size: file.size,
								location: formPostData.location,
								storageType: formPostData.storageType,
								attachmentGroupId: entity.attachmentGroup.id()
							};
							if (entity  && entity.id && entity.id()) {
								if (attachment.attachmentGroupId) {
									jQuery.ajax({
										url: Config.apiBaseUrl + 'attachments',
										type: 'POST',
										headers: {
											'Authorization' : 'Bearer ' + Config.sessionKey
										},
										data: JSON.stringify(attachment),
										dataType: 'json',
										contentType: "application/json",
										success: function(data,status,request) {
											entity.attachmentGroup.attachments.push(ko.mapping.fromJS(data));
										},
										error: function(data) {
											options.error('Error completing upload.');
										}
									});
								} else {
									jQuery.ajax({
										url: Config.apiBaseUrl + entity.attachmentGroup.entityName + '/' + entity.id(),
										type: 'PATCH',
										headers: {
											'Authorization' : 'Bearer ' + Config.sessionKey
										},
										data: JSON.stringify({
											attachmentGroup: {
												attachments: [attachment]
											}
										}),
										dataType: 'json',
										contentType: "application/json",
										success: function(data,status,request) {
											entity.attachmentGroup.id(data.attachmentGroup.id)
											for (var key in data.attachmentGroup.attachments) {
												var a = ko.mapping.fromJS(data.attachmentGroup.attachments[key]);
												entity.attachmentGroup.attachments.push(a);
											}
										},
										error: function(data) {
											options.error('Error completing upload.');
										}
									});
								}
							} else {
								entity.attachmentGroup.attachments.push(ko.mapping.fromJS(attachment));
							}
						});

						this.on('removedfile', function (file) {
							entity.attachmentGroup.attachments.remove(function(am) {
								return am.name === file.name;
							});
						});
					}

					$(element).dropzone(options);
				}
			};
		</script>

		<!-- Submit Ticket functionality *************************************************************************************** -->
		<script>
			/**************************************************************************************************************
			* Utility function to start a new Ticket in the Detail Slide Out.
			*/
			function startNewTicket(onClose) {
				viewModels.detailSlideOut().templateName(viewModels.detailSlideOut().defaultTemplate);
				viewModels.detailSlideOut().data({});
				viewModels.detailSlideOut().wasUpdated(false);

				setupActivityCategories();
				if(Config.isInternalUser){
					if (Config.contextType == 'accounts' && viewModels.data().name) {
						viewModels.accountSelectorList.push({
							id: Config.contextKey,
							name: viewModels.data().name()
						});
						viewModels.data().newActivity.accountId(Config.contextKey);
					}
				}else{
					//add support for end user or impersonating SU
					viewModels.data().newActivity.accountId(Config.accountId);
				}

				viewModels.detailSlideOut().data(viewModels.data().newActivity);
				viewModels.detailSlideOut().templateName('crm.ticket.addNew');
				viewModels.detailSlideOut().onClose = onClose || function() {};
				viewModels.detailSlideOut().open();
			};

			var submitTicketOptions = {
				title: "New Support Ticket",
				helpText: "",
				labels: {
					subject: "Subject",
					description: "Question or <br>Description of Problem",
					category: "Category",
					attachments: "Attachments",
					submitTicket: "Submit Ticket",
					ticketSubmitted: "Ticket submitted",
					manageTickets: "Manage Tickets",
					startNewCustomerTicket: "Add Another Ticket"
				},
				categoryHelpText: "Please select a category that best relates to your question or problem so that we can direct this ticket to the proper agent.",
				supportPhone: "",
				supportPhoneTollFree: "800-555-1212",
				ticketPostingMessage: "Please wait while the system processes your ticket.",
				ticketActivityTypeId: 15,
				ticketSuccessMessage: "Your ticket as been submitted."
			};
		
			function ticketIsValid() {
				var activity = viewModels.data().newActivity;
				return (activity.topic() && activity.description() && activity.workQueue() && activity.category());
			}
		
			function setupActivityCategories() {
				var categories = [];
				if(Config && Config.apiBaseUrl && Config.sessionKey) {
					jQuery.ajax({
						url: Config.apiBaseUrl + 'activityCategories?include=workQueue,workQueue.manager',
						cache: false,
						type: 'GET',
						headers: {
							'Authorization' : 'Bearer ' + Config.sessionKey
						},
						dataType: 'json',
						contentType: "application/json",
						success: function(data,status,request) {
							var groupedCategories = _.groupBy(data, 'parentCategory.id');
							categoriesVM.categoriesByParentId(groupedCategories);
							categoriesVM.selectors([new Selector(categoriesVM.categoriesByParentId()[undefined],0)]);
						},
						error: function(data) {
							console.log('Error getting activity categories');
						}
					});
				}
			}	
		
			function Selector(categories, index) {
				var self = this;
				self.index = index;
				self.categories = categories;
				self.selectedCategory = ko.observable();
				self.selectedCategory.subscribe( function(){
					categoriesVM.categoryChanged(self);
				});
			}
		
			function CategoriesViewModel() {
				var self = this;
				self.categoriesByParentId = ko.observable({});
				self.selectors = ko.observableArray([]);
				self.currentHelpText = ko.observable('');
				self.categoryChanged = function(selector) {
					// First remove all selectors after the one that was just changed
					self.selectors.remove(function(s) {return s.index > selector.index});
					// Set the currentHelpText from the selectedCategory's HelpText
					categoriesVM.currentHelpText(selector.selectedCategory() ? selector.selectedCategory().helpText : '');
					// If it is on the "select one...", return
					if(!selector.selectedCategory()) {
						viewModels.data().newActivity.category({});
						viewModels.data().newActivity.workQueue({});
						return;
					};
		
					// Then, if the category just selected has a work queue,
					if (selector.selectedCategory().workQueue) {
						// set the work queue and the category on the new Activity
						viewModels.data().newActivity.category(selector.selectedCategory());
						viewModels.data().newActivity.workQueue(selector.selectedCategory().workQueue);
					}
					// Othewise, add a new selector underneath that contains the next level of category choices
					else {
						self.selectors.push(new Selector(self.categoriesByParentId()[selector.selectedCategory().id],selector.index + 1));
					};
				};
			}
		
			function SubmitTicket() {
				viewModels.data().newActivity.wasSubmitted(true);
				viewModels.data().newActivity.activityType({ id: submitTicketOptions.ticketActivityTypeId }); //Ticket
		
				if (!viewModels.data().newActivity.onBehalfOf()) {
					viewModels.data().newActivity.onBehalfOf({ id: Config.customerKey});
				}
				viewModels.data().createActivity({}, viewModels.data().newActivity.submitTicketCallback);
			}
		
			var categoriesVM = new CategoriesViewModel();
		
		</script>

	<!-- 
	********************************************************************************************************************************************
	********************************************************************************************************************************************

									Knockout Templates

	********************************************************************************************************************************************
	********************************************************************************************************************************************
	-->

		<!-- List of Activity Detail Cards **************************************************************************** -->
		<script type="text/html" id="crm.activities">
			<!-- ko if: viewModels.activityTypes() && viewModels.activityTypes().length > 0 -->
				<div class="timeline-filter">
					<ul class="nav nav-pills">
						<li data-bind="css: { active: $data.activityTypeFilter() == '' }">
							<a href="#0" data-bind="click: function(){ $data.filterActivities('') }">All</a>
						</li>
						<!-- ko foreach: viewModels.activityTypes -->
						<li data-bind="css: { active: viewModels.data().activityTypeFilter() == id }">
							<a href="#0" data-bind="text: utils.plural(displayName), click: function(){ viewModels.data().filterActivities(id) }"></a>
						</li>
						<!-- /ko -->
					</ul>
				</div>
			<!-- /ko -->

			<!-- ko if: $data.activities().length > 0 -->
				<div class="timeline" data-bind="foreach: $data.activities">
					<!-- ko template: 'crm.activity.detail.card' -->
					<!-- /ko -->
				</div>
				<!-- ko if: $data.activities().length > 10 -->
					<div class="timeline-footer text-center">
						<a href="#tab=activities" class="btn btn-large">View all activities</a>
					</div>
				<!-- /ko -->
			<!-- /ko -->

			<!-- ko ifnot: $data.activities().length > 0 -->
				<div class="card card-transparent text-center" style="padding: 20px;">
					<span class="text-large muted">
						<i class="icon-list-alt icon-large icon-fixed-width"></i> There aren't any items to display
					</span>
				</div>
			<!-- /ko -->
		</script>

		<!-- Activity Detail Card ************************************************************************************* -->
		<script type="text/html" id="crm.activity.detail.card">
			<div class="timeline-item">
				<div class="timeline-indicator">
					<i data-bind="css: activityType.activityIcon, attr: { title: activityType.name }"></i>
				</div>
				<div class="media card" data-bind="if: $data">
					<div class="card-actions text-center">
						<a href="#0" data-bind="click: view">View &amp; Edit</a>
						<div class="muted">
							<small data-bind="text: utils.plural('Comment', notes().length, true)"></small>
						</div>
					</div>
					<!-- ko template: { name: 'crm.activity.detail.userAvatar', data: createdBy } --><!-- /ko -->
					<div class="media-body">
						<div data-bind="template: 'crm.activity.card.heading'"></div>
						<div class="media-heading text-bold" data-bind="visible: showTopic">
							<span data-bind="html: topic"></span>
						</div>
						<div class="card-form">
							<div class="card-description">
								<div class="pre" data-bind="html: description, readmore: {
									collapsedHeight: 60,
									moreLink: '<a href=#0 class=text-small>View more</a>',
									lessLink: '<a href=#0 class=text-small>View less</a>'
								}"></div>
							</div>
							<div data-bind="template: 'crm.activity.attachments'"></div>
						</div>
					</div>
				</div>
			</div>
		</script>

		<!-- Activity Detail Card Heading ************************************************************************************* -->
		<script type="text/html" id="crm.activity.card.heading" >
			<div class="media-heading">
				<div>Logged by <b data-bind="text: Utilities.userFullName(createdBy)"></b></div>
				<small data-bind="text: 'Last Modified: ' + Utilities.formatDateTime(dateModified())"></small>
			</div>
		</script>

		<!-- Activity Attachments Templates ************************************************************************************* -->
		<script type="text/html" id="crm.activity.attachments">
			<div data-bind="template: {name: 'crm.attachments.list', data: {allowEdits: false, model:$data, showAttachmentsLabel: true}}"></div>
		</script>

		<script type="text/html" id="crm.attachments.list">
			<div data-bind="if: model.attachmentGroup">
				<label data-bind="visible: (model.attachmentGroup.attachments().length > 0 || allowEdits) && showAttachmentsLabel">Attachments</label>
				<div class="labels text-small">
					<!-- ko if: model.attachmentGroup -->
						<!-- <button
							class="btn btn-link"
							data-toggle="collapse"
							data-bind="visible: model.attachmentGroup.attachments().length > 3, attr: { 'data-target': '#attachments_' + model.attachmentGroup.id() }">
								<span data-bind="text: model.attachmentGroup.attachments().length"></span> attachments <i class="icon-angle-down"></i>
						</button>
						<div data-bind="css: { 'collapse': model.attachmentGroup.attachments().length > 3 }, attr: { id: 'attachments_' + model.attachmentGroup.id() }"> -->

							<!-- ko foreach: model.attachmentGroup.attachments -->
								<!-- ko template: {name: 'crm.attachments.detail', data: {model:$data, allowEdits: $parent.allowEdits, attachmentGroup: $parent.model.attachmentGroup}} --><!-- /ko -->
							<!-- /ko -->

						<!-- </div> -->
					<!-- /ko -->
				</div>
			</div>
		</script>

		<script type="text/html" id="crm.attachments.addModal">
			<div class="dropzone" data-bind="attachmentUpload: {
				value: $data
			}"></div>
		</script>

		<script type="text/html" id="crm.attachments.detail" >
			<!-- ko if: model.relativeDownloadUrl -->
				<a class="label label-default" data-bind="attr: { href: model.relativeDownloadUrl, title: model.name }">
					<!-- ko template: 'crm.attachments.item' --><!-- /ko -->
				</a>
			<!-- /ko -->

			<!-- ko ifnot: model.relativeDownloadUrl -->
				<span class="label label-default">
					<!-- ko template: 'crm.attachments.item' --><!-- /ko -->
				</span>
			<!-- /ko -->
		</script>

		<script type="text/html" id="crm.attachments.item" >
			<span data-bind="template: {name: 'crm.attachments.icon', data: model}"></span>
			<span data-bind="text: model.name().length > 20 ? model.name().substr(0, 20) + '...' + model.name().substr(model.name().lastIndexOf('.') + 1) : model.name()"></span>
			<!-- ko if: allowEdits -->
				<i class="icon-remove" title="Remove attachment" data-bind="visible: allowEdits, click: attachmentGroup.removeAttachment"></i>
			<!-- /ko -->
		</script>

		<script type="text/html" id="crm.attachments.icon" >
			<!-- ko ifnot: type().split('/')[0] == '' -->
				<span data-bind="template: 'crm.attachments.icon.' + type().split('/')[0]"></span>
			<!-- /ko -->
		</script>

		<script type="text/html" id="crm.attachments.icon.image" >
			<i class="icon-picture" aria-hidden="true"></i>
		</script>
		<script type="text/html" id="crm.attachments.icon.text" >
			<i class="icon-file-text" aria-hidden="true"></i>
		</script>
		<script type="text/html" id="crm.attachments.icon.audio" >
			<i class="icon-music" aria-hidden="true"></i>
		</script>
		<script type="text/html" id="crm.attachments.icon.video" >
			<i class="icon-facetime-video" aria-hidden="true"></i>
		</script>
		<script type="text/html" id="crm.attachments.icon.application" >
			<i class="icon-file" aria-hidden="true"></i>
		</script>

		<!-- New Activity Template **************************************************************************************** -->
		<script type="text/html" id="crm.newActivity.logActivity">
			<div id="logActivityTab" class="tab-pane card-form active">
				<div data-bind="template: {name:'crm.activity.newNote', data: {placeholderText:'Start typing to log an activity...', model: $data, logType: 'activity'}}"></div>

				<div class="collapse" data-bind="css: { 'in': showOptions() && description() }">

					<div class="row-fluid">
						<div class="span12">
							<label for="topic">Subject</label>
							<input type="text" class="card-input input-block-level" data-bind="value: topic">
						</div>
					</div>
					<div class="row-fluid">
						<div class="span6">
							<label for="dateOfActivity">Date and time</label>
							<div class="input-prepend date form_datetime"
									data-date-format="m/dd/yyyy H:ii P"
									data-bind="datetimepicker: {
										weekStart: 1,
										todayBtn:  0,
										autoclose: 1,
										todayHighlight: 1,
										startView: 'month',
										forceParse: 0,
										showMeridian: 1,
										minuteStep: 15
									}">
								<span class="add-on"><i class="icon-calendar"></i></span>
								<input type="text"
										id="dateOfActivity"
										class="input-block-level"
										data-bind="value: dateOfActivity">
							</div>
						</div>
						<div data-bind="template: {name: 'crm.activity.requiredMembers' }" class="span6"></div>
					</div>
					<div class="row-fluid">
						<div class="span6">
							<label>Tags</label>
							<select class="input-block-level card-input" multiple placeholder="Start typing to search"
								data-bind="selectize: viewModels.activityTags,
										selectedOptions: $data.tags,
										options: {plugins: ['remove_button'], dropdownParent: 'body'},
										optionsText: 'name',
										optionsValue: 'id'">
							</select>
						</div>
						<div data-bind="template: {name: 'crm.activity.members' }" class="span6"></div>
					</div>
					<div class="row-fluid">
						<div class="span12">
							<label>Related to</label>
							<!-- ko if: relatedTo.length > 0 -->
								<p data-bind="fastForEach: relatedTo">
									<span class="label label-default"><i data-bind="css: Utilities.getIconFromEntityType(type())"></i> <span data-bind="text: name"></span></span>
								</p>
							<!-- /ko -->
						</div>
					</div>
				</div>

				<div class="card-form-actions" data-bind="visible: description">
					<button id="activity_post" class="btn btn-primary" data-bind="click: updateActivity">
						Save activity
					</button>
					<button class="btn btn-link" data-bind="click: cancelChanges" >Cancel</button>
				</div>

			</div>
		</script>

		<!-- PROTOTYPE: New Email Activity Template **************************************************************************************** -->
		<script type="text/html" id="crm.newActivity.email">
			<div id="sendEmailTab" class="tab-pane">
				<!-- <div data-bind="template: 'crm.activity.members'"></div> -->
				<div class="card-form">
					<div class="pull-right cc-bcc">
						<button class="btn btn-link" data-toggle="collapse" data-target="#email_cc">Cc Bcc</button>
					</div>
					<select class="card-input input-block-level" spellcheck="false" multiple placeholder="To"
						data-bind="selectize: availableMembers,
								selectedOptions: memberUsers,
								options: {plugins: ['remove_button']},
								optionsText: 'fullName',
								optionsValue: 'id'">
					</select>
					<div id="email_cc" class="collapse">
						<input type="text" class="card-input input-block-level" spellcheck="false" placeholder="Cc">
						<input type="text" class="card-input input-block-level" spellcheck="false" placeholder="Bcc">
					</div>
					<input type="text" class="card-input input-block-level" spellcheck="false" readonly value="From Brian Siedel (brian.seidel@websitepipeline.com)">
					<input type="text" class="card-input input-block-level" spellcheck="false" placeholder="Subject" data-bind="value: topic">
					<textarea rows="2" class="card-input input-block-level stretchy" placeholder="Your message here..." data-bind="value: internalComment"></textarea>
				</div>
				<div class="card-form">
					<div class="row-fluid">
						<!-- <div class="span4">
							<label>Type of activity</label>
							<select class="input-block-level"
								data-bind="options: viewModels.activityTypes,
										optionsText: 'name',
										optionsValue: 'id',
										valueAllowUnset: true,
										value: activityType.id"></select>
						</div> -->
						<div class="span5">
							<label>Related to</label>
							<!-- ko if: relatedTo.length > 0 -->
							<div data-bind="fastForEach: relatedTo">
								<span class="label label-default"><i data-bind="css: Utilities.getIconFromEntityType(type())"></i> <span data-bind="text: name"></span></span>
							</div>
							<!-- /ko -->
						</div>
						<div class="span7">
							<div data-bind="template: {name: 'crm.attachments.list', data: {model:$data, allowEdits: true, showAttachmentsLabel: true}}"></div>
						</div>
					</div>
				</div>
				<div class="card-form-actions">
					<button class="btn btn-primary" data-bind="click: updateActivity">Send email</button>
					<button class="btn btn-link" data-bind="click: cancelChanges" >Cancel</button>
				</div>
			</div>
		</script>

		<!-- PROTOTYPE: New Phone Call Activity Template **************************************************************************************** -->
		<script type="text/html" id="crm.newActivity.phoneCall">
			<div id="makeCallTab" class="tab-pane">
				<div data-bind:="with: viewModels.data">
					<label>Call From<label>
					<select id="callFrom">
						<!-- ko if: currentUser.phoneNumber -->
							<option data-bind="text: 'Main: ' + currentUser.phoneNumber, value: currentUser.phoneNumber"></option>
						<!-- /ko -->
						<!-- ko if: currentUser.MobilePhoneNumber -->
							<option data-bind=", text: 'Mobile: ' + currentUser.mobilePhoneNumber, value: currentUser.mobilePhoneNumber"></option>
						<!-- /ko -->
					</select>
					<div data-bind="if: $data.phoneNumber">
						<span class="label"><i data-bind="css: Utilities.getIconFromEntityType(Config.contextType)"></i> <span data-bind="text: name"></span></span>
						<a class="pull-right" data-toggle="modal" data-target="#modalCalling"
								style="margin-top: 7px;" data-bind="click: dial(Config.contextType, Config.contextKey, name())">Call <span data-bind="text: phoneNumber"></span></a>
					</div>
				</div>

				<div data-bind="template: 'crm.newActivity.phoneCall.contactList'"></div>

				<div id="modalCalling" class="modal modal-small fade" data-backdrop="static">
					<div class="modal-body text-center">
						<h4>Calling</h4>
						<h3 data-bind="text: viewModels.calling"></h3>
						<div class="sk-three-bounce">
							<div class="sk-child sk-bounce1"></div>
							<div class="sk-child sk-bounce2"></div>
							<div class="sk-child sk-bounce3"></div>
						</div>
						<!--<div class="text-center">
							<button class="btn btn-danger" data-dismiss="modal">Cancel</button>
							<button class="btn btn-primary">Log activity</button>
						</div>-->
					</div>
				</div>
			</div>
		</script>

		<script type="text/html" id ="crm.newActivity.phoneCall.contactList">
			<div class="media-list" data-bind="if: viewModels.isUsersLoaded">
				<div class="card-title">Account Contacts</div>
				<div data-bind="fastForEach: viewModels.users">
					<div data-bind="template: 'crm.newActivity.phoneCall.contactList.contact'"></div>
				</div>
			</div>
		</script>

		<script type="text/html" id ="crm.newActivity.phoneCall.contactList.contact">
			<div class="media">
				<div class="pull-right">
					<div data-bind="if: phoneNumber">
						<a data-toggle="modal" data-target="#modalCalling"
							style="margin-top: 7px;" data-bind="click: dial('users', id(), fullName())">Call <span data-bind="text: phoneNumber"></span></a>
					</div>
					<div data-bind="ifnot: phoneNumber">
						<a style="margin-top: 7px;" data-bind="attr: { href: 'contact_edit.asp?c_key=' + id() }">Setup contact</a>
					</div>
				</div>
				<!--<img src="http://i.pravatar.cc/50?img=45" alt="" class="pull-left img-circle">-->
				<div class="media-body">
					<b class="media-heading" data-bind="text: fullName"></b><br>
					<small class="muted" data-bind="text: jobTitle"></small>
				</div>
			</div>
		</script>

		<!-- PROTOTYPE: New Task Activity Template **************************************************************************************** -->
		<script type="text/html" id="crm.newActivity.task">
			<div class="card-form row-fluid">
				<div class="span7">
					<input type="text" class="card-input input-block-level" placeholder="A short but descriptive task name">
				</div>
				<div class="span5">
					<div class="input-prepend date form_datetime" data-date-format="m/dd/yyyy H:ii P" data-bind="datetimepicker: {
								weekStart: 1,
								todayBtn:  0,
								autoclose: 1,
								todayHighlight: 1,
								startView: 'month',
								forceParse: 0,
								showMeridian: 1,
								minuteStep: 15
							}">
						<span class="add-on"><i class="icon-calendar"></i></span>
						<input size="16" type="text" class="input-block-level" placeholder="Due date/time">
					</div>
				</div>
			</div>
			<textarea rows="1" class="card-input input-block-level stretchy" placeholder="Full description of the task..."></textarea>
			<div class="card-form row-fluid">
				<div class="span5">
					<label>Type</label>
					<select class="card-input input-block-level">
						<option value="call">Call</option>
						<option value="email">Email</option>
						<option value="todo">To-do</option>
					</select>
				</div>
				<div class="span7">
					<label>Assigned to</label>
					<select class="card-input input-block-level">
						<option value="bks">Brian Seidel</option>
						<option value="dm">Don Martin</option>
						<option value="ela">Eric Alexander</option>
					</select>
				</div>
			</div>
			<div class="card-form row-fluid">
				<div class="span5">
					<label>Work queue</label>
					<select class="card-input input-block-level">
						<option value="bo">Business Operations</option>
						<option value="des">Design</option>
						<option value="dev">Development</option>
						<option value="mkt">Marketing</option>
						<option value="sal">Sales</option>
					</select>
				</div>
				<div class="span7">
					<label>Send reminder</label>
					<select class="card-input input-auto">
						<option value="">Day of</option>
						<option value="">Day before</option>
						<option value="">Week before</option>
						<option value="">No reminder</option>
					</select>
					<div class="input-prepend date form_datetime" style="width: auto;" data-date-format="H:ii P" data-bind="datetimepicker: {
								weekStart: 1,
								todayBtn:  0,
								autoclose: 1,
								todayHighlight: 0,
								startView: 'hour',
								forceParse: 0,
								showMeridian: 1,
								minuteStep: 15,
								maxView: 'hour',
								pickDate: false
							}">
						<span class="add-on"><i class="icon-time"></i></span>
						<input size="16" type="text" class="input-block-level" data-bind="value: moment(new Date()).format('h:mm A')">
					</div>
				</div>
			</div>
			<div class="card-form row-fluid">
				<div class="span5">
					<label>Related to</label>
					<span class="label label-default"><i class="icon-building"></i> Website Pipeline</span>
				</div>
				<div class="span7">
					<label>Members</label>
					<select class="input-block-level card-input" multiple placeholder="Start typing to search"
						data-bind="selectize: availableMembers,
								selectedOptions: memberUsers,
								options: {plugins: ['remove_button']},
								optionsText: 'fullName',
								optionsValue: 'id'">
					</select>
				</div>
			</div>
			<div class="card-form row-fluid">
				<div class="span12">
					<div data-bind="template: {name: 'crm.attachments.list', data: {model:$data, allowEdits: true, showAttachmentsLabel: true}}"></div>
				</div>
			</div>
			<div class="card-form-actions">
				<button class="btn btn-primary">Create task</button>
				<button class="btn btn-link">Cancel</button>
			</div>
		</script>

		<!-- PROTOTYPE: New Schedule Activity Template **************************************************************************************** -->
		<script type="text/html" id="crm.newActivity.schedule">
			<div class="row-fluid card-form">
				<div class="span7">
					<input type="text" class="card-input input-block-level" placeholder="Topic or subject of meeting">
				</div>
				<div class="span5">
					<div class="input-prepend date form_datetime" data-date-format="m/dd/yyyy H:ii P" data-bind="datetimepicker: {
								weekStart: 1,
								todayBtn:  0,
								autoclose: 1,
								todayHighlight: 1,
								startView: 'month',
								forceParse: 0,
								showMeridian: 1,
								minuteStep: 15
							}">
						<span class="add-on"><i class="icon-calendar"></i></span>
						<input size="16" type="text" class="input-block-level" placeholder="Meeting date/time">
					</div>
				</div>
			</div>
			<textarea rows="1" class="card-input input-block-level stretchy" placeholder="Notes..."></textarea>
			<div class="card-form row-fluid">
				<div class="span4">
					<label>Related to</label>
					<span class="label label-default"><i class="icon-building"></i> Website Pipeline</span>
				</div>
				<div class="span8">
					<label>Attendees</label>
					<select class="input-block-level card-input" multiple placeholder="Start typing to search"
						data-bind="selectize: availableMembers,
								selectedOptions: memberUsers,
								options: {plugins: ['remove_button']},
								optionsText: 'fullName',
								optionsValue: 'id'">
					</select>
				</div>
			</div>
			<div class="card-form-actions">
				<button class="btn btn-primary">Schedule meeting</button>
				<button class="btn btn-link">Cancel</button>
			</div>
		</script>


		<!-- Main Interation Tracker Template ****************************************************************************** -->

		<script type="text/html" id="cim.tab.dashboard">
            <div class="sk-three-bounce" data-bind="visible: Config.contextKey && !viewModels.data().id">
                <div class="sk-child sk-bounce1"></div>
                <div class="sk-child sk-bounce2"></div>
                <div class="sk-child sk-bounce3"></div>
            </div>
            <div id="interaction-tracker">
                <!-- ko if: Config.contextKey && viewModels.data().id -->
                    <!-- ko template: { name:'crm.interactionTracker', data: viewModels} --><!-- /ko -->
                <!-- /ko -->
            </div>
            <div id="interaction-log">
                <!-- ko if: Config.contextKey && viewModels.data().activities -->
                    <!-- ko template: { name:'crm.activities', data: viewModels.data()} --><!-- /ko -->
                <!-- /ko -->
            </div>
        </script>

		<script type="text/html" id="crm.interactionTracker">

			<div class="card" data-bind="ElementQueries, with: viewModels.data().newActivity">
				<!-- <ul class="nav nav-tabs">
					<li class="active"><a href="#logActivityTab" data-toggle="tab"><i class="icon-edit"></i> Log<span> Activity</span></a></li>
					<li><a href="#sendEmailTab" data-toggle="tab"><i class="icon-envelope"></i> <span>Send </span>Email</a></li>
					<li><a href="#makeCallTab" data-toggle="tab"><i class="icon-phone"></i> <span>Make </span>Call</a></li>
					<li><a href="#createTaskTab" data-toggle="tab"><i class="icon-check"></i> <span>Create </span>Task</a></li>
					<li><a href="#scheduleTab" data-toggle="tab"><i class="icon-calendar"></i> Schedule</a></li>
				</ul> -->
				<div class="tab-content">
					<div id="logActivityTab" class="tab-pane active" data-bind="template: 'crm.newActivity.logActivity'"></div>
					<div id="sendEmailTab" class="tab-pane" data-bind="template: 'crm.newActivity.email'"></div>
					<div id="makeCallTab" class="tab-pane" data-bind="template: 'crm.newActivity.phoneCall'"></div>
					<div id="createTaskTab" class="tab-pane" data-bind="template: 'crm.newActivity.task'"></div>
					<div id="scheduleTab" class="tab-pane" data-bind="template: 'crm.newActivity.schedule'"></div>
				</div>
			</div>
		</script>

		<!-- *********************************************************************************************************************
				Activity Detail Templates 
			**********************************************************************************************************************-->
		
		<!-- Activity Detail Main Template *********************************************************************************** -->
		<script type="text/html" id="crm.activity.detail">
			<div class="datagrid-detail-header" data-bind="template:'crm.activity.detail.header'"></div>
			<div class="datagrid-detail-body">
				<div class="datagrid-detail-content" data-bind="template:'crm.activity.detail.content'"></div>
				<div class="datagrid-detail-sidebar" data-bind="
					template: 'crm.activity.detail.sidebar', 
					css: { 'open': viewModels.detailSlideOut().sidebarOpen() }
				"></div>
			</div>
		</script>

		<!-- Activity Detail Header Template ******************************************************************************* -->
		<script type="text/html" id="crm.activity.detail.header">
			<!-- ko template: 'crm.detail.slideOut.close' --><!-- /ko -->
			<!-- ko template: 'crm.detail.slideOut.sidebarToggle' --><!-- /ko -->
			<h3 class="interaction-tracker__title">Activity Detail</h3>
		</script>

		<!-- Activity Detail Sidebar Template ****************************************************************************** -->
		<script type="text/html" id="crm.activity.detail.sidebar">
			<div data-bind="template: 'crm.activity.detail.createdBy'"></div>
			<div data-bind="template: 'crm.activity.detail.sidebar.attachments'"></div>
			<div data-bind="template: 'crm.activity.detail.sidebar.details'"></div>
		</script>

		<!-- Activity Detail Content Template ****************************************************************************** -->
		<script type="text/html" id="crm.activity.detail.content">
			<div class="thread-list">
				<div class="thread-list-item">
					<div class="media">
						<span class="pull-left media-object" data-bind="template: {name: 'crm.activity.detail.userAvatar', data: createdBy }"></span>
						<div class="media-body">
							<small class="pull-right muted" data-bind="text: dateOfActivity"></small>
							<div class="thread-author">
								<span data-bind="text: createdBy.fullName"></span> 
								<small>logged an activity</small>
							</div>
							<div class="btn-group pull-right">
								<button class="btn btn-link" data-bind="click: edit, visible: !isEditing()">Edit</button>
							</div>
							<p class="lead editable" data-bind="editableHTML: topic, attr: { contenteditable: isEditing }"></p>
							<div class="thread-content editable"
								data-bind="editableHTML: description, attr: { contenteditable: isEditing },
									readmore: {
										collapsedHeight: 80,
										moreLink: '<a href=\'#0\' class=\'text-small\'>View more</a>',
										lessLink: '<a href=\'#0\' class=\'text-small\'>View less</a>'
									}">
								
							</div>
							<div data-bind="visible: isEditing">
								<button class="btn btn-primary" data-bind="click: updateActivity">
									Update
								</button>
								<button class="btn btn-link" data-bind="click: cancelChanges" >Cancel</button>
							</div>
						</div>
					</div>
				</div>

				<!-- TODO responsive -->
				<div class="card thread-list-item" data-bind="template:'crm.activity.detail.newNote'"></div>
				<!-- TODO responsive -->

				<div data-bind="template: 'crm.activity.detail.combinedLog'"></div>
				
			</div>
		</script>

		<!-- Activity Detail Created By Template ****************************************************************************** -->
		<script type="text/html" id="crm.activity.detail.createdBy">
			<ul class="icons-ul">
				<li data-bind="with: createdBy"><h5>Logged By</h5><i class="icon-li icon-user"></i><span data-bind="text: fullName"></span></li>
				<li data-bind="with: account">
					<h5>Account</h5>
					<i class="icon-li icon-building"></i>
					<span data-bind="text: name"></span>
					<small class="muted" data-bind="click: function(){ $parent.account('') }">change</small>
				</li>
				<li data-bind="if: !(account() && account() != {})">
					<h5>Account</h5>
					<!-- ko ifnot: (account() && account() != {}) -->
						<label>Choose an Account</label>
						<div data-bind="">
							<div data-bind="template: 'crm.activity.accountSelector'"></div>
						</div>
						<div data-bind="if: relatedTo.length > 0">
							<div data-bind="fastForEach: relatedTo">
								<span class="label label-default">
									<i data-bind="css: Utilities.getIconFromEntityType(type())"></i>
									<span data-bind="text: name"></span>
								</span>
							</div>
						</div>
					<!-- /ko -->
				</li>
			</ul>
		</script>

		<!-- Activity Detail Sidebar Attachments Template ********************************************************************* -->
		<script type="text/html" id="crm.activity.detail.sidebar.attachments">
			<div data-bind="if: $data.attachmentGroup.attachments().length > 0">
				<hr>
				<h5>Attachments</h5>
				<div data-bind="template: {name: 'crm.attachments.list', data: {allowEdits: false, model:$data, showAttachmentsLabel: false}}"></div>
			</div>
		</script>

		<!-- Activity Detail Sidebar Details Template ********************************************************************** -->
		<script type="text/html" id="crm.activity.detail.sidebar.details">
			<hr>
			<h5>Activity Details</h5>
			<div class="card-form">
				<label for="dateOfActivity">Date and time</label>
				<div class="input-prepend date form_datetime"
						data-date-format="m/dd/yyyy H:ii P"
						data-bind="datetimepicker: {
							weekStart: 1,
							todayBtn:  0,
							autoclose: 1,
							todayHighlight: 1,
							startView: 'month',
							forceParse: 0,
							showMeridian: 1,
							minuteStep: 15
						}">
					<span class="add-on"><i class="icon-calendar"></i></span>
					<input type="text"
							id="dateOfActivity"
							class="input-block-level"
							data-bind="value: dateOfActivity">
				</div>

				<div data-bind="template: {name: 'crm.activity.requiredMembers' }"></div>
				<div data-bind="template: {name: 'crm.activity.members' }"></div>

				<label>Tags</label>
				<select class="input-block-level card-input" multiple placeholder="Start typing to search"
					data-bind="selectize: viewModels.activityTags,
							selectedOptions: $data.tags,
							options: {plugins: ['remove_button'], dropdownParent: 'body'},
							optionsText: 'name',
							optionsValue: 'id'">
				</select>
			</div>
			<div class="card-form-actions">
				<button id="activity_post" class="btn btn-primary" data-bind="click: updateActivity">
					Update activity
				</button>
				<button class="btn btn-link" data-bind="click: cancelChanges" >Cancel</button>
			</div>
		</script>

		<!-- Activity Detail New Note Template *************************************************************************************************** -->
		<script type="text/html" id="crm.activity.detail.newNote">
			<div class="card-form clearfix">
				<textarea 
					data-bind="textInput: newNote.internalComment" 
					class="input-block-level stretchy -full-width-input is-note" 
					rows="3" 
					placeholder="Add an internal comment here"
					style="padding: 15px;">
				</textarea>
				<div class="collapse hidden-note-options" data-bind="template: {name: 'crm.note.mentions', data: newNote}"></div>
				<div class="row-fluid">
					<div class="span5">
						<ul class="nav nav-pills text-small" style="margin-bottom: 10px;">
							<li>
								<a href="#0" data-bind="click: newNote.attachmentGroup.add">
									<i class="icon-paperclip"></i> Attach files
								</a>
							</li>
							<li data-bind="visible: !newNote.externalComment()">
								<a href=".hidden-note-options" class="collapsed" data-toggle="collapse">
									More Options
								</a>
							</li>
						</ul>
					</div>
					<div class="span7 text-right">
						<p>
							<button
								class="btn"
								data-bind="click:  function(){ viewModels.data().addNote($data) },
											css: { 'btn-primary': newNote.isValid },
											enable: newNote.isValid,
											text: 'Add Comment' + (newNote.internalComment() && newNote.externalComment() ? 's' : '')">
							</button>
						</p>
					</div>
				</div>
				<div class="row-fluid" data-bind="visible: newNote.attachmentGroup.attachments().length > 0">
					<div class="span12">
						<div data-bind="template: {name: 'crm.attachments.list', data: {model:newNote, allowEdits: true, showAttachmentsLabel: true}}"></div>
					</div>
				</div>
			</div>
		</script>

		<!-- Activity Detail Notes Template *************************************************************************************************** -->
		<script type="text/html" id="crm.activity.detail.combinedLog">
			<div class="thread-list-item clearfix">
				<ul class="unstyled text-small pull-right" style="margin: 0;">
					<li>
						<a href="#0" data-bind="event: {click: (logSortOrder() == 'desc' ? sortLog : sortLog('desc'))}">
							<span data-bind="text: (logSortOrder() == 'desc') ? 'Newest first' : 'Oldest first'"></span>
							<i class="icon-sort-by-attributes icon-fixed-width"></i>
						</a>
					</li>
				</ul>
			</div>
			<div data-bind="fastForEach: combinedLog">
				<div data-bind="template:'crm.ticket.detail.externalNote'"></div>
				<div data-bind="template: 'crm.ticket.detail.internalNote'"></div>
				<div data-bind="template: 'crm.ticket.detail.changeLog'"></div>
			</div>
		</script>

		<!-- Misc Activity Templates ****************************************************************************** -->
		<script type="text/html" id="crm.activity.members">
			<label>Optional Members</label>
			<select class="input-block-level card-input" multiple placeholder="Start typing to search"
				data-bind="selectize: availableMembers,
						selectedOptions: memberUsers,
						options: {
							plugins: ['remove_button'], 
							dropdownParent: 'body', 
							render: {
								option: function(item, escape) {
									if (item.superUser) {
										return '<div><i class=\'icon-group muted pull-right\' title=\'Super User\'></i>' 
													+ escape(item.fullName) 
													+ '</div>'
									} else {
										return '<div>' + escape(item.fullName) + '</div>'
									}
								}, 
								item: function(item, escape) {
									if (item.superUser) {
										return '<div>' 
													+ escape(item.fullName) 
													+ ' <i class=\'icon-group icon-fixed-width muted\' title=\'Super User\'></i></div>'
									} else {
										return '<div>' + escape(item.fullName) + '</div>'
									}
								}
							}
						},
						optionsText: 'fullName',
						optionsValue: 'id'">
			</select>
		</script>

		<script type="text/html" id="crm.activity.requiredMembers">
			<label>Required Members</label>
			<div class="card-input labels" data-bind="foreach: requiredMemberUsers">
				<span class="label label-default"  data-bind="text: name"></span>
			</div>
		</script>

		<script type="text/html" id="crm.note.mentions">
			<label>Notify Via Email</label>
			<select class="input-block-level card-input" multiple placeholder="Start typing to search"
				data-bind="selectize: availableMembers,
						selectedOptions: mentions,
						options: {
							plugins: ['remove_button'], 
							dropdownParent: 'body', 
							render: {
								option: function(item, escape) {
									if (item.superUser) {
										return '<div><i class=\'icon-group muted pull-right\' title=\'Super User\'></i>' 
													+ escape(item.fullName) 
													+ '</div>'
									} else {
										return '<div>' + escape(item.fullName) + '</div>'
									}
								}, 
								item: function(item, escape) {
									if (item.superUser) {
										return '<div>' 
													+ escape(item.fullName) 
													+ ' <i class=\'icon-group icon-fixed-width muted\' title=\'Super User\'></i></div>'
									} else {
										return '<div>' + escape(item.fullName) + '</div>'
									}
								}
							}
						},
						optionsText: 'fullName',
						optionsValue: 'id'">
			</select>
		</script>

		<script type="text/html" id="crm.activity.newNote">
			<textarea
				class="card-input input-block-level stretchy"
				rows="1"
				data-bind="textInput: model.description, attr: {placeholder: placeholderText}"
				autofocus style="margin-bottom: 5px;"
			></textarea>

			<div data-bind="visible: model.description">
				<ul class="nav nav-pills text-small text-right" style="margin-bottom: 10px;">
					<li>
						<a href="#0" data-bind="click: model.attachmentGroup.add">
							<i class="icon-paperclip"></i> Attach files
						</a>
					</li>
					<li>
						<a href="#0" data-bind="click: function() { model.showOptions(!model.showOptions()) }">
							More options <i class="icon-angle-down icon-fixed-width" data-bind="css: { 'icon-angle-down': !model.showOptions(), 'icon-angle-up': model.showOptions }"></i>
						</a>
					</li>
				</ul>
			</div>

			<!-- ko if: model.attachmentGroup.attachments().length > 0 -->
				<div class="row-fluid">
					<div class="span12">
						<div data-bind="template: {name: 'crm.attachments.list', data: {model:model, allowEdits: true, showAttachmentsLabel: true}}"></div>
					</div>
				</div>
			<!-- /ko -->
		</script>

		<script type="text/html" id="crm.activity.detail.userAvatar">
			<!-- This template expects the $data to be a User -->
			<div 
				class="media-object pull-left thread-avatar" 
				data-bind="text: Utilities.userInitials($data), 
						style: { 'background-color': Utilities.userAvatar($data) }">
			</div>
		</script>

		<script type="text/html" id="crm.activity.accountSelector">
			<div class="card-form">
				<select class="input-block-level card-input" placeholder="Start typing to search" 
					data-bind="selectize: viewModels.accountSelectorList,
							optionsText: 'name',
							optionsValue: 'id',
							options: {
								dropdownParent: 'body',
								load: Utilities.searchAccounts
							},
							value: accountId">
				</select>
			</div>
		</script>

		<script type="text/html" id="crm.activity.onBehalfOfSelector">
			<div>
				<select class="input-block-level card-input"
					data-bind="options: viewModels.accountUsers,
							optionsText: 'fullName',
							optionsCaption: '[Not Set]',
							valueAllowUnset: true,
							value: onBehalfOf">
				</select>
			</div>
		</script>
		
		<!-- *********************************************************************************************************************
				Ticket Detail Templates 
			**********************************************************************************************************************-->
		
		<!-- Ticket Detail Main Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail">
			<!-- ko if: viewModels.errors().length -->
				<div class="thread-list" data-bind="foreach: viewModels.errors">
					<h3 data-bind="text: text"></h3>
				</div>	
			<!-- /ko -->
		
			<!-- ko ifnot: viewModels.errors().length -->
				<div class="datagrid-detail-header" data-bind="template:'crm.ticket.detail.header'"></div>
				<div class="datagrid-detail-body">
					<div class="datagrid-detail-content" data-bind="template:'crm.ticket.detail.content'"></div>
					<!-- ko if: currentUser.isInternalUser -->
						<div class="datagrid-detail-sidebar" data-bind="
							template:'crm.ticket.detail.sidebar', 
							css: { 'open': viewModels.detailSlideOut().sidebarOpen() }
						"></div>
					<!-- /ko -->
				</div>
			<!-- /ko -->
		</script>

		<!-- Ticket Detail Header Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.header">
			<!-- ko template: 'crm.detail.slideOut.close' --><!-- /ko -->
			<!-- ko template: 'crm.detail.slideOut.sidebarToggle' --><!-- /ko -->
			<h3 class="interaction-tracker__title">Ticket Detail</h3>
			<span class="label label-default" data-bind="text: '#' + id()"></span>&nbsp;
			<span data-bind="with: lifecycleStage">
				<span data-bind="attr: { class: cssClass }, text: name "></span>
			</span>
		</script>

		<!-- Ticket Detail Content Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.content">
			<div class="thread-list">
				<div class="thread-list-item" style="border: 0;">
					<div class="media">
						<span class="pull-left media-object" data-bind="template: {name: 'crm.activity.detail.userAvatar', data: createdBy }"></span>
						<div class="media-body">
							<small class="pull-right muted" data-bind="text: dateOfActivity"></small>
							<div class="thread-author">
								<span data-bind="text: createdBy.fullName"></span> 
								<small>submitted a ticket</small>
								<span data-bind="if: onBehalfOf() != null && createdBy.id() !== onBehalfOf().id">
									<small> on behalf of </small>
									<span data-bind="text: onBehalfOf().fullName"></span> 
								</span>
							</div>
							<p class="lead" data-bind="text: topic"></p>
							<div class="thread-content" data-bind="html: description, readmore: {
								collapsedHeight: 80,
								moreLink: '<a href=\'#0\' class=\'text-small\'>View more</a>',
								lessLink: '<a href=\'#0\' class=\'text-small\'>View less</a>'
							}"></div>
						</div>
					</div>
				</div>

				<!-- TODO responsive -->
				<div class="card thread-list-item clearfix" data-bind="template:'crm.ticket.detail.newNote'"></div>
				<!-- TODO responsive -->

				<div data-bind="template: 'crm.activity.detail.combinedLog'"></div>
				
			</div>
		</script>

		<!-- Ticket Detail New Note Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.newNote">
			<div class="card-form">
				<textarea 
					data-bind="textInput: newNote.externalComment" 
					class="input-block-level stretchy" 
					rows="3" 
					placeholder="Type your reply here" 
					autofocus 
					style="padding: 15px;">
				</textarea>
				
				<div class="row-fluid">
					<div class="span5">
						<ul class="nav nav-pills text-small" style="margin-bottom: 10px;">
							<li>
								<a href="#0" data-bind="click: newNote.attachmentGroup.add">
									<i class="icon-paperclip"></i> Attach files
								</a>
							</li>
							<!-- ko if: currentUser.isInternalUser -->
							<li data-bind="visible: !newNote.internalComment()">
								<a href="#internalComment" class="collapsed" data-toggle="collapse">
									Add internal note
								</a>
							</li>
							<!-- /ko -->
						</ul>
					</div>
					<div class="span7 text-right">
						<p>
							<button
								class="btn"
								data-bind="click:  function(){ viewModels.data().addNote($data) },
											css: { 'btn-primary': newNote.isValid },
											enable: newNote.isValid,
											text: newNote.buttonText">
							</button>
						</p>
					</div>
				</div>
				<div class="row-fluid" data-bind="visible: newNote.attachmentGroup.attachments().length > 0">
					<div class="span12">
						<div data-bind="template: {name: 'crm.attachments.list', data: {model:newNote, allowEdits: true, showAttachmentsLabel: true}}"></div>
					</div>
				</div>
			</div>
		</script>

		<!-- Ticket Detail Change Log Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.changeLog">
			<div data-bind="if: $data.fromData && $data.fromData() && $data.toData && $data.toData()">
							
				<div class="alert alert-bar without-close">
					<div class="alert-icon hidden-xs">
						<i class="icon-flag"></i>
					</div>
					<small class="pull-right" data-bind="text: Utilities.formatDateTime(dateCreated())"></small>
					<b data-bind="text: changedBy.fullName"></b> changed:
					<div class="media-body text-small">
						<div data-bind="if: propertyChanged.lifecycleStage">
							- Status from 
							<b data-bind="text: fromData().lifecycleStage ? fromData().lifecycleStage.name : '[Not set]'"></b>
							to <b data-bind="text: toData().lifecycleStage ? toData().lifecycleStage.name : '[Not set]'"></b>.
						</div>
						<div data-bind="if: propertyChanged.priority">
							- Priority from 
							<b data-bind="text: fromData().priority ? fromData().priority.name : '[Not set]' "></b>
							to <b data-bind="text: toData().priority ? toData().priority.name : '[Not set]' "></b>.
						</div>
						<div data-bind="if: propertyChanged.workQueue">
							- Work queue from 
							<b data-bind="text: fromData().workQueue ? fromData().workQueue.name : '[Not set]' "></b>
							to <b data-bind="text: toData().workQueue ? toData().workQueue.name : '[Not set]' "></b>.
						</div>
						<div data-bind="if: propertyChanged.category">
							- Category from 
							<b data-bind="text: fromData().category ? fromData().category.name : '[Not set]' "></b>
							to <b data-bind="text: toData().category ? toData().category.name : '[Not set]' "></b>.
						</div>
						<div data-bind="if: propertyChanged.assignedTo">
							- Assignee from 
							<b data-bind="text: fromData().assignedTo
										? fromData().assignedTo.firstName + ' ' + fromData().assignedTo.lastName 
										: '[Unassigned]' "></b>
							to <b data-bind="text: toData().assignedTo 
										? toData().assignedTo.firstName + ' ' + toData().assignedTo.lastName 
										: '[Unassigned]' "></b>.
						</div>
						<div data-bind="if: propertyChanged.onBehalfOf">
							- Customer from 
							<b data-bind="text: fromData().onBehalfOf
										? fromData().onBehalfOf.firstName + ' ' + fromData().onBehalfOf.lastName 
										: '[Not Set]' "></b>
							to <b data-bind="text: toData().onBehalfOf 
										? toData().onBehalfOf.firstName + ' ' + toData().onBehalfOf.lastName 
										: '[Not Set]' "></b>.
						</div>
				</div>
				</div>
							
			</div>
		</script>

		<!-- Ticket Detail Internal Note Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.internalNote">
			<!-- This will only show if there is internalText and NOT externalText (since the externalNote template also has internalText) -->
			<div data-bind="if: $data.internalText && $data.internalText().trim() && !($data.externalText && $data.externalText().trim()) ">
				<div class="thread-list-item is-note">
					<div class="media">
						<span data-bind="visible: !externalText(), template: {name: 'crm.activity.detail.userAvatar', data: createdBy }"></span>		
						<div class="media-body">
							<small class="pull-right muted" data-bind="visible: !externalText(), text: Utilities.formatDateTime(dateCreated())"></small>
							<div class="thread-author">
								<span data-bind="text: createdBy.fullName"></span>
								<small>added a note:</small>
							</div>
							<div class="thread-content">
								<div class="thread-content-text" data-bind="html: internalText, readmore: {
										collapsedHeight: 80,
										moreLink: '<a href=\'#0\' class=\'text-small\'>View more</a>',
										lessLink: '<a href=\'#0\' class=\'text-small\'>View less</a>'
									}">
								</div>
							</div>	
							<div class="thread-attachments text-small" data-bind=" foreach: attachmentGroup.attachments">
								<!-- ko template: {name: 'crm.attachments.detail', data: {model:$data, allowEdits: false, attachmentGroup: $parent}} --><!-- /ko -->
							</div>
						</div>
					</div>
				</div>
			</div>
		</script>

		<!-- Ticket Detail External Note Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.externalNote">
			<div data-bind="if: $data.externalText && $data.externalText().trim()">
				<div class="thread-list-item">
					<div class="media">
						<div 
							class="media-object pull-left thread-avatar"
							data-bind="text: Utilities.userInitials($data.createdBy), style: { 'background-color': Utilities.userAvatar($data.createdBy) }"></div>
						<div class="media-body">
							<small class="pull-right muted" data-bind="text: Utilities.formatDateTime(dateCreated())"></small>
							<div class="thread-author">
								<span data-bind="text: createdBy.fullName"></span> 
								<small>replied:</small>
							</div>
							<div class="thread-content">
								<div class="thread-content-text" data-bind="html: externalText, readmore: {
										collapsedHeight: 80,
										moreLink: '<a href=\'#0\' class=\'text-small\'>View more</a>',
										lessLink: '<a href=\'#0\' class=\'text-small\'>View less</a>'
									}">
								</div>
							</div>
							<div data-bind="if: $data.internalText && $data.internalText().trim()">
								<div class="thread-content is-note">
									<div class="thread-content-text" data-bind="html: internalText, readmore: {
											collapsedHeight: 80,
											moreLink: '<a href=\'#0\' class=\'text-small\'>View more</a>',
											lessLink: '<a href=\'#0\' class=\'text-small\'>View less</a>'
										}">
									</div>	
								</div>
							</div>
							<div class="thread-attachments text-small" data-bind=" foreach: attachmentGroup.attachments">
								<!-- ko template: {name: 'crm.attachments.detail', data: {model:$data, allowEdits: false, attachmentGroup: $parent}} --><!-- /ko -->
							</div>
						</div>
					</div>
				</div>
			</div>
		</script>

		<!-- Ticket Detail Attachments Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.attachments">
			<div data-bind="visible: attachmentGroup.attachments().length > 0">
				<label>Attachments</label>
				<div data-bind=" foreach: attachmentGroup.attachments">
					<!-- ko template: {name: 'crm.attachments.detail', data: {model:$data, allowEdits: false, attachmentGroup: $parent}} --><!-- /ko -->
				</div>
			</div>
		</script>

		<!-- Ticket Detail Sidebar Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.sidebar">
			<div data-bind="template: 'crm.ticket.detail.userInfo'"></div>
			<div data-bind="template: 'crm.activity.detail.sidebar.attachments'"></div>
			<div data-bind="template: 'crm.ticket.detail.sidebarDetails'"></div>
		</script>

		<!-- Ticket Detail User Info Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.userInfo">
			<h4>Customer Info</h4>
			<ul class="icons-ul">
				<li data-bind="with: onBehalfOf"><i class="icon-li icon-user"></i><span data-bind="text: fullName"></span></li>
				<li data-bind="with: account"><i class="icon-li icon-building"></i><span data-bind="text: name"></span></li>
			</ul>
		</script>

		<!-- Ticket Detail Sidebar Details Template *************************************************************************************************** -->
		<script type="text/html" id="crm.ticket.detail.sidebarDetails">
			<hr>
			<h4>Ticket Details</h4>
			
			<div class="card-form">	
				<div data-bind="template: {name: 'crm.activity.requiredMembers' }"></div>	
				<label>Customer Contact</label>
				<div data-bind="template: 'crm.activity.onBehalfOfSelector'"></div>
				<label>Stage</label>
				<select class="card-input input-block-level"
					data-bind="options: viewModels.activityLifecycleStages,
							optionsText: 'name',
							valueAllowUnset: true,
							value: lifecycleStage">
				</select>
				<label>Priority</label>
				<select class="card-input input-block-level"
					data-bind="options: viewModels.activityPriorities,
							optionsText: 'name',
							valueAllowUnset: true,
							value: priority">
				</select>
				<label>Work Queue</label>
				<select class="card-input input-block-level"
					data-bind="options: viewModels.activityWorkQueues,
							optionsText: 'name',
							valueAllowUnset: true,
							value: workQueue">
				</select>
				<label>Category</label>
				<select class="card-input input-block-level"
					data-bind="options: viewModels.activityCategories,
							optionsText: 'name',
							valueAllowUnset: true,
							value: category">
				</select>
				<label>Assigned To</label>
				<select class="card-input input-block-level"
					data-bind="options: viewModels.activityAssignees,
							optionsText: function(user) { return user.fullName + ' (' + user.username + ')'; },
							optionsCaption: '[Unassigned]',
							valueAllowUnset: true,
							value: assignedTo">
				</select>
				<button
					class="btn btn-primary"
					data-bind="click: updateTicket">
					Update Ticket
				</button>
				<button
					class="btn btn-link"
					data-bind="click: cancelChanges">
					Cancel
				</button>
			</div>
		</script>

		<!-- *********************************************************************************************************************
				New Ticket Templates 
			**********************************************************************************************************************-->

		<!-- New Ticket Main Template (for Slide Out) -->
		<script type="text/html" id="crm.ticket.addNew">
			<div data-bind="with:viewModels.data().newActivity">
				<div class="datagrid-detail-header" >
					<!-- ko template: 'crm.detail.slideOut.close' --><!-- /ko -->
					<!-- ko template: 'crm.tickets.newTicket.header' --><!-- /ko -->
				</div>
				<div class="datagrid-detail-body" data-bind="ifnot: wasSubmitted" >
					<!-- ko template: 'crm.tickets.newTicket.form' --><!-- /ko -->
				</div>
				<div class="datagrid-detail-body" data-bind="if: wasSubmitted">
					<div class="form-horizontal">
						<h1 data-bind="text: submitTicketOptions.labels.ticketSubmitted"></h1>
						<button class="btn" data-bind="click: startNewTicket, text: submitTicketOptions.labels.startNewCustomerTicket"></button>
						<a class="btn" href="manage_tickets.asp" data-bind="text: submitTicketOptions.labels.manageTickets"></a>
						<button class="btn" data-bind="click: viewModels.detailSlideOut().close">Close</button>
					</div>
				</div>
			</div>
		</script>

		<!-- Submit Ticket Header -->
		<script type="text/html" id="crm.tickets.newTicket.header">
			<h3 data-bind="text: submitTicketOptions.title"></h3>
		</script>

		<!-- Submit Ticket Main Form -->
		<script type="text/html" id="crm.tickets.newTicket.form">
			<div data-bind="text: submitTicketOptions.helpText, visible: submitTicketOptions.helpText.length > 0"></div>
			<div class="form-horizontal">
				<div data-bind="if: currentUser.isInternalUser">
					<div class="control-group">
						<label class="control-label">Account</label>
						<div class="account-selector">
							<div data-bind="template: 'crm.activity.accountSelector'"></div>
						</div>
					</div>
					<div class="control-group">
						<label class="control-label">User</label>
						<div class="controls">
							<div data-bind="template: 'crm.activity.onBehalfOfSelector'"></div>
						</div>
					</div>
				</div>
				<div class="control-group">
					<label class="control-label" data-bind="html: submitTicketOptions.labels.subject"></label>
					<div class="controls">
						<input type="text" class="card-input input-block-level" data-bind="textInput: topic"> 
					</div>
				</div>
				<div class="control-group">
					<div class="control-label"></div>
					<div class="controls">
						<p class="help-block" data-bind="text: submitTicketOptions.categoryHelpText"></p>
					</div>
				</div>
				<div class="control-group">
					<label class="control-label" data-bind="html: submitTicketOptions.labels.category"></label>
					<div data-bind="template: 'crm.tickets.newTicket.categories'"></div>
				</div>
				<div class="control-group">
					<label class="control-label" data-bind="html: submitTicketOptions.labels.description"></label>
					<div class="controls">
						<textarea class="card-input input-block-level stretchy" style="min-height: 50px;" 
							data-bind="textInput: description"></textarea> 
						<!-- ko with: categoriesVM.currentHelpText -->
							<p class="help-block" data-bind="html: $data"></p>
						<!-- /ko -->
					</div>
				</div>
				<div class="control-group">
					<label class="control-label" data-bind="html: submitTicketOptions.labels.attachments"></label>
					<div class="controls">
						<a href="#0" data-bind="click: attachmentGroup.add">
							<i class="icon-paperclip"></i> Attach files
						</a>
						<div data-bind="template: {name: 'crm.attachments.list', data: {allowEdits: true, model:$data, showAttachmentsLabel: false}}"></div>
					</div>
				</div>
				<div class="form-actions">
					<button id="ticket_submit" class="btn" 
						data-bind="click: SubmitTicket, 
								text: submitTicketOptions.labels.submitTicket,
								css: { 'btn-primary': ticketIsValid() },
								enable: ticketIsValid()"></button> 
				</div>
			</div>
		</script>

		<!-- Categories Template for New Ticket -->
		<script type="text/html" id="crm.tickets.newTicket.categories">
			<div data-bind="with: categoriesVM">
				<div data-bind="foreach: selectors">
					<div data-bind="template: 'crm.tickets.newTicket.category-selector'"></div>
				</div>
			</div>
		</script>
		
		<!-- Category Selector for Categories Template -->
		<script type="text/html" id="crm.tickets.newTicket.category-selector">
			<select 
				class="card-input input-block-level" 
				style="margin-bottom: 7px;"
				size="1"
				data-bind="options: categories,
						optionsText: 'displayText',
						value: selectedCategory,
						optionsCaption: index == 0 ? 'Select a category...' : 'Additional category...'",>
			</select>
		</script>

		<!-- *********************************************************************************************************************
			Other Templates 
		**********************************************************************************************************************-->

		<!-- Detail Slideout Close Button ****************************************************************************** -->
		<script type="text/html" id="crm.detail.slideOut.close">
			<button class="interaction-tracker__close" data-bind="click: viewModels.detailSlideOut().close">
				<i class="fas fa-times"></i>
			</button>
		</script>
		
		<!-- Detail Slideout Sidebar Toggle Button ****************************************************************************** -->
		<script type="text/html" id="crm.detail.slideOut.sidebarToggle">
			<a href="#0" 
				class="datagrid-detail-sidebar-toggle hidden-lg hidden-xl" 
				title="Toggle Details" 
				data-bind="
					tooltip: { placement: 'left', delay: { show: 1000 } },
					click: viewModels.detailSlideOut().toggleSidebar,
					css: { 'muted': !viewModels.detailSlideOut().sidebarOpen() }">
				<i class="icon-info-sign icon-large icon-fixed-width"></i>
			</a>
		</script>

		<!-- Account Templates ********************************************************************************************* -->
		<script type="text/html" id="crm.accounts.title">
			<div class="card">
				<div style="display: flex;">
					<i class="muted icon-building icon-fixed-width icon-4x" style="margin-right: 10px;"></i>
					<div style="flex-grow: 1;">
						<div class="media-heading">
							<h1 data-bind="html: name"></h1>
						</div>
						<div data-bind="visible: url">
							<a data-bind="href: url">
								<i class="icon-globe"></i> <span data-bind="text: url"></span>
							</a>
						</div>
					</div>
				</div>
			</div>
		</script>

		<script type="text/html" id="crm.accounts">
			<div id="accountdetail" class="media card" data-bind="with: viewModels.data()">
				<div class="card-title">Account Detail</div>
				<div data-bind="
					readmore: {
						collapsedHeight: 100,
						moreLink: '<a href=\'#0\' class=\'btn btn-link\'>View more</a>',
						lessLink: '<a href=\'#0\' class=\'btn btn-link\'>View less</a>'
					}">
					<table class="table">
						<tbody>
							<!--<tr>
								<td>Website</td>
								<td><a href="#0">www.websitepipeline.com</a></td>
							</tr>
							<tr>
								<td>Primary Contact</td>
								<td><a href="#0">Mollie Woodside</a></td>
							</tr>
							<tr>
								<td>Location</td>
								<td>Greenville, SC USA</td>
							</tr>-->
							<tr>
								<td>Phone</td>
								<td data-bind="text: phoneNumber"></td>
							</tr>
							<tr>
								<td>Account Number</td>
								<td data-bind="text: number"></td>
							</tr>
							<tr>
								<td>Division</td>
								<td data-bind="text: division"></td>
							</tr>
							<tr>
								<td>Address</td>
								<td>
									<span data-bind="text: addressLine1"></span><!-- ko if: addressLine2--><br><!-- /ko -->
									<span data-bind="text: addressLine2"></span><!-- ko if: addressLine3--><br><!-- /ko -->
									<span data-bind="text: addressLine3"></span><br>
									<span data-bind="text: city"></span>, <span data-bind="text: stateProvince"></span> <span data-bind="text: postalCode"></span>
								</td>
							</tr>
							<!--<tr>
								<td>Payment Terms</td>
								<td>99</td>
							</tr>-->
						</tbody>
					</table>
				</div>
			</div>
		</script>

		<!-- Address Templates ********************************************************************************************* -->
		<script type="text/html" id="crm.addresses.title">
			<div class="card">
				place holder
			</div>
		</script>

		<script type="text/html" id="crm.addresses">
			<div id="addressdetail" class="card">
				<div class="media">
					<i class="muted icon-building icon-fixed-width icon-4x pull-left"></i>
					<div class="media-body">
						<h4 class="media-heading" data-bind="html: name"></h4>
						<dl class="dl-horizontal">
							<dt>Address</dt>
							<dd data-bind="html: drawAddress($data)"></dd>
							<dt data-bind="if: phoneNumber">Phone</dt>
							<dd data-bind="if: phoneNumber">
									<a data-bind=" attr: { 'href' : 'tel: +1' + phoneNumber() }, html: phoneNumber"></a>
							</dd>
							<dt data-bind="if: emailAddress">Email</dt>
							<dd data-bind="if: emailAddress">
									<a data-bind="attr: { 'href' : 'mailto: ' + emailAddress() }, text: emailAddress "></a>
							</dd>
						</dl>
					</div>
				</div>
			</div>
		</script>

		<!-- Invoice Templates ********************************************************************************************* -->
		<script type="text/html" id="crm.invoices.title">
			<div class="card">
				place holder
			</div>
		</script>

		<script type="text/html" id="crm.invoices">

		</script>

		<!-- Inbox Templates ********************************************************************************************* -->
		<script type="text/html" id="crm.inbox.toggle">
			<a href="#0" data-sidebar="toggle" title="Notifications"
			class="crm-notif app-navicon with-badge ">
				<i class="fas fa-bell"></i>
				<span class="badge" data-bind="visible: activities().length, text: activities().length"></span>
			</a>
		</script>

		<script type="text/html" id="crm.inbox.card">
			<a href="#0" class="media card slide-over" data-bind="click: function() { $parent.selectActivity($data) }">
				<i class="icon-fixed-width icon-large pull-left"
					data-bind="css: activityType.activityIcon"></i>
				<div class="media-body">
					<div data-bind="template: 'crm.inbox.card.heading'"></div>
				</div>
			</a>
		</script>

		<script type="text/html" id="crm.inbox.card.heading" >
			<div class="media-heading">
				<div>
					<b data-bind="text: createdBy.fullName"></b> 
					<span data-bind="if: activityType.name() === 'Ticket'">
						submitted a ticket
					</span>
					<span data-bind="if: activityType.name() === 'Activity'">
						logged an activity
					</span>
				</div>
				<small data-bind="text: 'Last Modified: ' + Utilities.formatDateTime(dateModified())"></small>
			</div>
		</script>

		<script type="text/html" id="crm.inbox">
			<div class="activities__caught-up-wrapper flex-slider-frame" data-bind="visible: !activities().length">
				<p class="activities__caught-up"><i class="icon-ok"></i> All Caught Up!</p>
			</div>
			<div class="flex-slider-frame" data-bind="fastForEach: activities, css: { 'slide-left': selectedActivity }, visible: activities().length">
				<div data-bind="template: 'crm.inbox.card'"></div>
			</div>
			<div class="flex-slider-frame" data-bind="css: { 'slide-left': selectedActivity }, visible: activities().length">
				<div data-bind="if: selectedActivity()">
					<a href="#0" class="card back-to-viewport" data-bind="click: function() { selectActivity() }">
						<i class="icon-arrow-left icon-fixed-width icon-large"></i> Back
					</a>
					<div class="card" data-bind="with: selectedActivity">
						<div class="media-body">
							<div data-bind="template: 'crm.activity.card.heading'"></div>
							<div class="editable" data-bind="html: $data.lastNote && lastNote.internalText()"></div>
						</div>
						<div class="card-form-actions">
							<button class="btn pull-right" data-bind="click: clearNotification">Clear</button>
							<button class="btn btn-primary" data-bind="click: view">View</button>
						</div>
					</div>
				</div>
			</div>
		</script>
		
		<!-- *********************************************************************************************************************
				Modal and Slide Out Divs 
			**********************************************************************************************************************-->
		
		<!-- Modal Activity (for Inbox) ********************************************************************************************* -->
		<div id="modalActivity" class="modal modal-large hide" data-backdrop="static">
			<div class="modal-header">
				<button class="close" data-dismiss="modal">&times;</button>
				<h3 class="interaction-tracker__title">Activity</h3>
			</div>
			<div class="modal-body" style="min-height: 300px;" data-bind="with: viewModels.inbox().selectedActivity">
				<div data-bind="template: 'crm.activity.detail.card'"></div>
			</div>
			<div class="modal-footer">
			</div>
		</div>
		
		<!-- Detail Slide Out panel (Should this be here or in cim_dashboard.asp?) ******************************************************* -->
		<script type="text/html" id="crm.no.template">
			
		</script>

		<div id="detailSlideout" data-bind="with: viewModels.detailSlideOut">
			<div class="datagrid-detail" data-bind="css: { open: isOpen() }">
				<!-- ko template: { name: templateName, data: data } --><!-- /ko -->
			</div>
		</div>


	

</div>
<div class="catalog-templates-scripts">




	<script>

		utils.isMainProduct = function (product) {
			return product && ko.unwrap(viewModel.mainProduct) === product;
		};

		utils.buildQuickAddLink = function(product){
			var link = product.link();
			var orderKey = utils.getParameter('o_key');
			if(orderKey){
				orderKey = '&o_key=' + orderKey;
			}
			if(link.includes('?')){
				link += '&quickadd=true' + orderKey;
			}else{
				link += '?quickadd=true' + orderKey;
			}
			return link;
		};

		utils.setCookie = function (name, value) {
			//need to also set expiry date?
			document.cookie = name + '=' + value + ';path=/;';
		};

		// www.the-art-of-web.com/javascript/getcookie/
		utils.getCookie = function (name) {
			var re = new RegExp('\\b' + name + '=([^;]+)');
			var value = re.exec(document.cookie);
			return value ? unescape(value[1]) : undefined;
		};

		utils.isActiveQuote = ((utils.getParameter('modal') == '1' || utils.getParameter('modal', parent) == '1') && "".length == 32) && "" != "7C743E237AD14B3F9C9E236A7665CEC7";

		//http://stackoverflow.com/questions/5999118/add-or-update-query-string-parameter
		utils.setParameter = function (key, value, uriArg) {
			var uri = uriArg || window.location.toString();
			var re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i');
			var separator;
			if (uri.indexOf('?') === -1) {
				separator = '?';
			} else {
				if (uri[uri.length - 1] === '?') {
					separator = '';
				} else {
					separator = '&';
				}
			}
			if (uri.match(re)) {
				return uri.replace(re, '$1' + key + '=' + value + '$2');
			} else {
				return uri + separator + key + '=' + value;
			}
		};

		utils.handleImageError = function (img) {
			handleImageError(img, oConfig.noImagePath);
		};

		utils.drawHidePriceMessage = function(){
			return "";
		}

		utils.removeHTML = function(text){
			return $(text).text();
		}

		utils.decodeHTML = function(text) {
			return $('<textarea>').html(text).text()
		};

		utils.getStoredBreadcrumbs = function() {
			try {
				return JSON.parse(localStorage.getItem('breadcrumbs'));
			} catch(e) {
				return null;
			}
		};

		utils.setStoredBreadcrumbs = function(obj) {
			try {
				localStorage.setItem('breadcrumbs', JSON.stringify(obj));
			} catch(e) {
				// nothing to do if it didn't work
				console.error('failed to save breadcrumbs');
			}
		};

		utils.breadCrumbProperty = function(link) {
			if(link == '' || link === null){
				return '';
			} else {
				return 'itemListElement';
			}
		};

		utils.breadCrumbItemType = function(link) {
			if(link == '' || link === null){
				return '';
			} else {
				return 'ListItem';
			}
		};

		utils.pageUrl = location.pathname + location.search;
		if(utils.pageUrl.charAt(0) == '/') {
			utils.pageUrl = utils.pageUrl.substring(1);
		}
		utils.loginUrl = 'security_logon.asp?autopage=' + encodeURIComponent(utils.pageUrl);

		utils.formatMoney = (function (positiveExample, negativeExample) {
			/*
			This takes an example of a formatted currency and returns a function
			to format numbers in that same format. The first argument is the
			number 1111.2222 formatted with the desired default number of
			decimals. The second argument is the additive inverse of the first.
			For example:
			$1,111.22
			¥ 1,111.22
			€1.111,22
			1 111,22F
			*/
			'use strict';
			function buildFormatter(example) {
				var thousandsSeperator = getGroup(/1([^1]?)1/);
				var decimalSymbol = getGroup(/1([^12]?)2/);
				var decimalPlaces = (example.match(/2/g) || []).length;
				var thousandsRegex = /(\d)(?=(?:\d{3})+$)/g;

				var escapedDecimalSymbol = _.escapeRegExp(decimalSymbol);
				var symbolRegex = new RegExp('^([^1' + escapedDecimalSymbol + ']*).+?([^12' + escapedDecimalSymbol + ']*)$');
				var symbolMatch = symbolRegex.exec(example);
				var prefix = symbolMatch ? symbolMatch[1] || '' : '';
				var suffix = symbolMatch ? symbolMatch[2] || '' : '';
                var infoLost = 0;

				function getGroup(pattern) {
					var match = pattern.exec(example)
					return match ? match[1] : '';
				}

				function decimalToString(decimal, places) {
					if (!places) {
						return '';
					} else {
						var result = getZeroString(places);

						if (decimal) {
							// Converting to an integer and rounding helps with
							// floating point errors.
							var int = Math.round(decimal * Math.pow(10, places));
							// Because leading zeroes will be dropped after
							// converting to integer, the string needs to be
							// padded with zeroes after being converted to a
							// string.
							result = (result + int.toString()).slice(-places);
						}
                        if(int==Math.pow(10,places)) {
                            // in this case, we have to track a +1 to add to the result because "100" sliced down to 2 places loses info
							/*
							* 2020-07-22 - EJ - More info: This is due to things like utils.formatPrice(1.995, 2) returning 1.00 instead
							* of 2.00 or utils.formatPrice(1.9995, 3) returning 1.000 instead of 2.000
							* This is because the whole number is truncated, then the decimal is rounded and only the decimal portion
							* is added back to the whole number portion.
							* This means the rounded decimal portion is always 1 or less.  If it's less than 1 (ex .89) this works.
							* However, if it's 1.000, it would "lose" 1 since only the decimal portion is added back.
							* PS - Don't ask me about the original design, I didn't design it that way.  I only corrected the "if"
							*      statement above where it was hard-coded to 100 to be Math.pow(10,places) so it would work when
							*      rounded to something other than 2 decimal places.
							*/
                            infoLost = 1;
                        } else {
                            infoLost = 0;
                        }

						return decimalSymbol + result;
					}
				}

				function getZeroString(length) {
					var pow = Math.pow(10, length);
					return pow.toString().slice(1);
				}

				function addThousandsSeperator(integer) {
					return (integer + infoLost).toString().replace(thousandsRegex, '$1' + thousandsSeperator);
				}

				return function (value, places) {
					places = typeof places === 'undefined' ? decimalPlaces : parseInt(places);

					// Truncate the value to get the integer portion.
					var integer = value | 0;
					var decimal = decimalToString(value % 1, places); //do first because we need to know if info was lost.
					var number = addThousandsSeperator(integer) + decimal;
					return prefix + number + suffix;
				}
			}

			var formatPositive = buildFormatter(positiveExample);
			var formatNegative = buildFormatter(negativeExample);

			return function (value, places) {
				value = parseFloat(ko.unwrap(value));
				if (isNaN(value)) return value.toString();
				return (value < 0 ? formatNegative : formatPositive)(Math.abs(value), places);
			}
		}('$1,111.22', '($1,111.22)'));

		utils.formatPrice = _.partialRight(utils.formatMoney, parseInt(2));

		utils.scrollTo = function (elementArg) {
			var element = $(elementArg).first();
			if (!element.length) return;

			// If the element is in an inactive tab, make the tab active.
			utils.activateTab(element);

			$('html, body').animate({
					scrollTop: $(element[0]).offset().top - 120 //offset to account for header bar
			}, 500);

		};

		utils.activateTab = function (element) {
			var tab = element.hasClass('.tab-pane') ? element : element.closest('.tab-pane');
			if (!tab.length || tab.hasClass('active')) return;
			var id = tab.attr('id');
			tab
				.closest('.tabbable')
				.find('.nav-tabs > li > a')
				.filter('[href="#' + id + '"], [data-target="#' + id + '"]')
				.tab('show');
		}

		utils.plural = function (singularForm, quantifier, includeQuantity) {
			var quantifierValue = ko.unwrap(quantifier);
			var quantity = _.isArray(quantifierValue) ? quantifierValue.length : quantifier;
			return (includeQuantity ? quantity + ' ' : '') + attache.plural(singularForm, quantity);
		};

		utils.atcListButtonText = function() {
			if(utils.isActiveQuote) {
				return 'Add to ' + oConfig.labels.savedCarts;
			} else {
				return oConfig.labels.addToCartList || 'Add to Cart';
			}
		};

		utils.resetATCForm = function() {
			if(!runHook('catalogTemplatesOverrideResetATCForm', { utils: this })) {
				document.getElementById("atc_form").reset();
				_.forEach(viewModel.results(), function(result) {
					if (setSelectedQty()) {
						result.selectedQty(result.minQty() || 1);
					}else{
						result.selectedQty(undefined);
					}
					result.selectedQty.notifySubscribers();
				});
			}
		}

		utils.addToCart = function (details, cart, parentKey, useInstances) {

			function getQueryStringParameters() {
				var params = {
					type : 'v200add',
					sc_id : oConfig.overrideCartKey || oConfig.sessionData.sc_id,
					s_key : oConfig.sessionData.sessionKey,
					s_url : oConfig.sessionData.storefrontUrl,
					o_url : oConfig.sessionData.orderfrontUrl,
					createsessioncookie : '1',
					noredirect : '1',
					l_ws_key : '',
					mobile : 'no',
					action : 'postlogic',
					modal  : utils.getParameter("modal")
				};

				// Only one order detail can be edited at a time, so if there
				// are more than one, choose an arbitrary one to edit.
				var editedOrderDetail = _.find(details, 'configuratorEditData');
				if (editedOrderDetail) params.odeditkey = editedOrderDetail.configuratorEditData.od_id;

				if (cart) {
					_.assign(params, {
						type: 'add-to-saved-cart',
						o_id: cart.key,
						nickname: cart.nickname
					});
				}

				return params;
			}

			function getPostData() {
				var data = {};
				var productKeys = [];
				var instanceKeys = [];
				var instancesWithKeys = {};

				//' Force use instances on if it's off / undefined and we detect duplicate p_keys
				if(!useInstances && details.length) {
					var distinctProductKeys = details.reduce(function(distinctValues, detail, index) {
						if(distinctValues && distinctValues.indexOf(detail.key()) < 0)
						{
							distinctValues.push(detail.key());
						}
					}, []);

					if(distinctProductKeys && distinctProductKeys.length !== details.length) {
						//' Always use instances if we're adding the same product key to cart in one post
						useInstances = true;
					}
				}

				buildConfiguratorData = function(product) {

					/* config_json field example:
						{
							"question":"F4E82B1A5F5A4A3F915B6618A766754F",
							"questionText":"STRIKE (required)",
							"name":"6800_000_10",
							"answer":"790BA1B41D6E48ECB2A825CB02EDAB93",
							"answerText":"A - 4-7/8 ASA Strike",
							"question_erp_code":"10_001",
							"answer_erp_code":"01",
							"question_status":"True"
						}

						Full config_json structure:
						{ choices: [
							{ field1 },
							{ field2 }
						],
						  configType: 'cartoptions' // or 'configurator'
						}
					*/

					/*
					'	We're setting configType based on the customForm value,
					'	but we should never hit this code if it's true until we
					'	put configurator in KO.  This is here just in case or
					'	for future use.
					'   customForm not be ndefined if not on the product detail page.
					*/
					if(typeof customForm !== 'undefined' && !!customForm) {
						configType = 'configurator';
					} else {
						configType = 'cartoptions';
					}
					var configJson = {
										choices: [],
										configType: configType
									};
					var cartOptions = '';
					if(product.questions && product.questions().length > 0)  {
						product.questions().forEach(function(question) {
							configJsonQuestion = {
								question: question.q_key(),
								name: question.questionText(),
								questionText: question.questionText(),
								answerText: question.selectedAnswer(),
								question_status: true
							};
							if(question.erpCode()) {
								configJsonQuestion["question_erp_code"] = question.erpCode();
							}
							configJson.choices.push(configJsonQuestion);
							cartOptions += question.questionText() + "~" + question.selectedAnswer() + "|"
						});
					}
					return {
							configJson: configJson,
							cartOptions: cartOptions.slice(0, -1) // trim trailing pipe
					};
				}

				handleAddOnProducts = function(item){
					addOnProducts = [];
					if(item.selectedProduct().selectedAddOn && item.selectedProduct().selectedAddOn()){
						addOnProducts.push(item.selectedProduct().selectedAddOn());
					}else if(item.selectedProduct().selectedAddOns && item.selectedProduct().selectedAddOns().length > 0){
						_.forEach(item.selectedProduct().selectedAddOns(), function(item){
							addOnProducts.push(item);
						})
					}
					
					_.forEach(addOnProducts, function(item){
						//handle the add to cart for  addons
						prepareAddToCart(item);
					})
				}

				prepareAddToCart = function(product){
					var productKey = product.key();
					var minQty = product.minQty() || 1;
					var uom = ko.toJS(product.selectedUom());
					var lineKey = productKey;

					if(useInstances) {
						lineKey = utils.createGuid();
						var tempInstanceKey = item.instance || utils.createGuid();

						product.instanceKey = tempInstanceKey;
						product.lineKey = lineKey;

						instanceKeys.push(tempInstanceKey);

						if(!instancesWithKeys[tempInstanceKey]) {
							instancesWithKeys[tempInstanceKey] = [];
						}

						instancesWithKeys[tempInstanceKey].push(lineKey);

						data['instance_' + lineKey] = tempInstanceKey;
						data['p_id_' + lineKey] = productKey;
						data['remove_type_' + lineKey] = 'instance';
						data['instance_key_set'] = '1';
					}

					data['qty_' + lineKey] = product.selectedQty() || minQty;
					if(oConfig.useUom){
						data['uom_' + lineKey] = uom.description;
						if(uom.hasOwnProperty("UomId")) data['uom_id_' + lineKey] = uom.UomId;
						data['uom_conversion_' + lineKey] = uom.uom_conversion;
					}
					data['pw_id_' + lineKey] = ko.unwrap(product.selectedWarehouse().key) || oConfig.defaultWarehouse;

					if(product.type == 'child') {
						if(parentKey && product.key() !== parentKey) {
							data['parent_p_id_' + lineKey] = parentKey;
						} else if(product.parents && product.parents().length > 0){
							data['parent_p_id_' + lineKey] = product.parents()[0].key();
						}
					}

					data['url_' + lineKey]           = product.link();
					data['minqty_' + lineKey]        = product.minQty();
					data['maxqty_' + lineKey]        = product.maxQty();
					data['qty_increment_' + lineKey] = product.stepQty();

					_.assign(data, buildConfiguratorPostData(productKey));
					if (minQty != 1) data['min_order_qty_' + lineKey] = minQty;

					if(product.configuratorEditData && product.configuratorEditData.lineNumber) {
						data['line_number_' + lineKey] = product.configuratorEditData.lineNumber;
					}

					if(product.configuratorEditData && product.configuratorEditData.minQty) {
						data['minqty_' + lineKey] = product.configuratorEditData.minQty;
					}

					if(product.configuratorEditData && product.configuratorEditData.maxQty) {
						data['maxqty_' + lineKey] = product.configuratorEditData.maxQty;
					}

					if(product.configuratorEditData && product.configuratorEditData.qtyIncrement) {
						data['qty_increment_' + lineKey] = product.configuratorEditData.qtyIncrement;
					}

					if(product.configuratorEditData && product.configuratorEditData.removeType) {
						data['remove_type_' + lineKey] = product.configuratorEditData.removeType;
					}

					if(product.configuratorEditData && product.configuratorEditData.priceCalcType) {
						data['price_calc_type_' + lineKey] = product.configuratorEditData.priceCalcType;
						if(product.configuratorEditData.priceCalcType == 'fixed') {
							data['price_' + lineKey] = product.configuratorEditData.price;
						}
					}

					if(product.questions && product.questions().length > 0 && product.hasCartOptions()) {
						var configData = buildConfiguratorData(product);
						data['config_json_' + lineKey] = JSON.stringify(configData.configJson);
						data['cart_option_' + lineKey] = configData.cartOptions;
					}

					productKeys.push(lineKey); //This needs to be above the hook so that the order in which the items are added to cart will persist. - cainb 2019-01-23 12:35:49
				}

				_.forEach(details, function (item) {

					if(oConfig.detailConfig.useAddOnProducts && item.showAddOns){
						handleAddOnProducts(item);
					}
					prepareAddToCart(item.selectedProduct());

					runHook('getPostDataBeforeReturn', { self: self, data: data, product: item.selectedProduct(), productKeys: productKeys });

				});

				data.keys = _.uniq(productKeys).join(',');

				if(instanceKeys.length) {
					data.instances = _.uniq(instanceKeys).join(',');

					for(key in instancesWithKeys) {
						data[key + '_keys'] = instancesWithKeys[key].join(',');
					}
				}

				return data;
			}

			function getAjaxConfig() {
				return {
					url: 'i_i_add_to_cart.asp?' + $.param(getQueryStringParameters()),
					type: 'POST',
					data: $.param(getPostData(), true),  // true forces jquery to not add brackets to array keys
					headers: {
						'X-Requested-With': 'XMLHttpRequest',
						'Accept': 'application/json, text/plain, * / *',
						'Content-Type': 'application/x-www-form-urlencoded'
					}
				};
			}

			function logSummary() {
				var cartName = cart ? ' "' + cart.nickname + '"' : '';
				console.log('Products added to cart' + cartName + ':\n' + _.map(details, function (product) {
					return '\tQty: ' + product.selectedQty() + ' - ' + product.name();
				}).join('\n'));
			}

			function successHandler(responseData, status, request) {
				var cartLines = JSON.parse(responseData)[1].detailLines;
				var newCart = [];
				_.each(cartLines, function(line){
					newCart.push({
						prod_key: line.productID,
						parent_p_id: line.parentProductID,
						qty: line.qty,
						od_key: line.orderDetailKey
					})
				});

				if(oConfig.t_gtm) {
					var gtmProducts = [];
					_.forEach(details, function (item) {

						var gtmProduct = {
							'name': item.name(),
							'id': item.sku(),
							'price': item.unitPrice(),
							'quantity': Number(item.selectedQty())
						}
						gtmProducts.push(gtmProduct);
					});

					if (gtmProducts.length >= 1) {
						window.dataLayer.push({
							'event': oConfig.t_gtm_add_to_cart_event_name,
							'ecommerce': {
								'currencyCode': 'USD',
								'add': {
									'products': gtmProducts
								}
							},
							'customer': {
								'email': cimcloud.session.email,
								'firstname': cimcloud.session.firstName,
								'lastname': cimcloud.session.lastName
							}
						});
					}
				}

				if(oConfig.isModal) {
					parent.modal.done([newCart]);
					try{
						parent.fncReloadCartWindow();
					}catch(err){
					}
					parent.top.utils.toastrATC(details, newCart);
				}else{
					viewModel.activeCart(newCart);

					if(viewModel.mainProduct && viewModel.mainProduct.configuratorEditData) {
						window.location = 'showcart.asp';
						return;
					}
					if(!cart) {
						try{
							fncReloadCartWindow();
						}catch(err){

						}
						if(typeof ofConfig === "undefined" || !ofConfig.stopToastrATC) {
							utils.toastrATC(details, cart);
						}
					} else {
						utils.modalATC(cart, data, details);
					}
					if(oConfig.pageName == 'pc_combined_results.asp' && isActiveLayout('list')) {
						utils.resetATCForm();
					}

					logSummary();

					toggleLoadingWidget(false);

					//render promo messaging template and display if applicable.
					element = utils.renderTemplateToContainer('catalog.promo_bar', data);

					runHook('addToCartSuccessHandler', { self: self, responseData: responseData, details: details });
				}
			}

			function errorHandler(responseData, status, request) {
				logSummary();

				var errorToastrConfig = {
					'closeButton': true,
					'newestOnTop': true,
					'positionClass': 'toast-top-right',
					'preventDuplicates': false,
					'showDuration': 200,
					'hideDuration': 1000,
					'tapToDismiss': true,
					'timeOut': 3000,
					'extendedTimeOut': 1000
				}

				toggleLoadingWidget(false);

				console.log(responseData);

				toastr.error(
					'Unable to add product to cart',
					'There was an error',
					errorToastrConfig
				);

			}
			var bPass = true;

			// TODO: add UoM support (qty_display, etc). Fields aren't available on the UoM Price objects yet.
			if (!_.isArray(details)) {
				details = [ details ];
			}
			var data = {
				details: details,
				cart: cart
			};

			var questionsValid = true;

			details.some(function(detail) {
				if(detail.hasOwnProperty("questionsHaveValidAnswers")) {
					questionsValid = detail.questionsHaveValidAnswers();

					if(!questionsValid) {
						detail.atcErrorText("Required option fields missing.");
					} else {
						detail.atcErrorText("");
					}

					if(!questionsValid && detail.hasOwnProperty("currentParent")) {
						detail.currentParent().rowsAtcAttempted(true);
					}
				}
				return !questionsValid;
			});

			if(!questionsValid) {
				return false;
			}

			if(details.length > 0 && details[0].useConfigurator()){
				/*
					doing an [eval] on an undefined throws an error.
					so, we have to try-catch.
						The template may be overriden to allow a product (with configurator)
						to be added to cart w/o any config options selected.
				*/
				try {
					if(!eval('formValidation' + oConfig.formValidationKey).check()){
						bPass = false;
					}
				} catch(e) {
					//not using FormBuilder
				}
			}else if(details.length <= 0) {
				bPass = false;
			}

			if(bPass){
				toggleLoadingWidget(true);
				cart = ko.toJS(cart);

				var promise = $.ajax(getAjaxConfig())
					.error(errorHandler)
					.done(successHandler);

				return promise;

			}else{
				return false;
			}
		};

		utils.popToastr = function(title, subtext, config) {

			var confirmToastrConfig = config ? config : {
				'closeButton': true,
				'newestOnTop': true,
				'positionClass': 'toast-top-right',
				'preventDuplicates': false,
				'showDuration': 200,
				'hideDuration': 1000,
				'tapToDismiss': false,
				'timeOut': 3000,
				'extendedTimeOut': 1000
			};

			toastr.success(
				subtext,
				title,
				confirmToastrConfig
			);
		};

		utils.popToastrError = function(title, subtext, config) {
			var errorToastrConfig = {
				'closeButton': true,
				'newestOnTop': true,
				'positionClass': 'toast-top-right',
				'preventDuplicates': false,
				'showDuration': 200,
				'hideDuration': 1000,
				'tapToDismiss': true,
				'timeOut': 3000,
				'extendedTimeOut': 1000
			}

			$.extend(errorToastrConfig, config);

			toggleLoadingWidget(false);

			toastr.error(
				subtext,
				title,
				errorToastrConfig
			);
		}

		utils.toastrATC = function(details, cart) {
			if(utils.isActiveQuote){
				var sPage = oConfig.sessionData.orderfrontUrl + '/' + "payment.asp?o_key=" + oConfig.overrideCartKey;
			}else{
				var sPage = oConfig.sessionData.orderfrontUrl + '/' + "showcart.asp";
			}

			if(utils.isActiveQuote && oConfig.isModal){
				sPage = "javascript:window.history.back();"
			}
			var confirmToastrConfig = {
				'closeButton': true,
				'newestOnTop': true,
				'onclick': function() {
					window.location = sPage;
				},
				'positionClass': 'toast-top-right',
				'preventDuplicates': false,
				'showDuration': 200,
				'hideDuration': 1000,
				'tapToDismiss': false,
				'timeOut': 3000,
				'extendedTimeOut': 1000
			}

			if(cart) {
				var confirmTextConfig =  {title: utils.plural(oConfig.labels.savedCartsLabels.itemText, details, true) + ' ' + oConfig.labels.savedCartsLabels.modalConfirmationHeader }
			}else{
				if(utils.isActiveQuote){
					var confirmTextConfig = { title: utils.plural(' product', details, true) + ' added to ' + oConfig.labels.savedCarts }
				}else{
					var confirmTextConfig = { title: utils.plural(' product', details, true) + ' added to Cart'}
				}
			};

			runHook('toastrATCConfiguration', { confirmToastrConfig: confirmToastrConfig, confirmTextConfig: confirmTextConfig });

			utils.popToastr(
				confirmTextConfig.title,
				'Click or tap to view',
				confirmToastrConfig
			);
		}

		utils.modalATC = function(cart, data, details) {
			var modalConfig = cart ?
			{
				body: 'catalog.saved_cart_confirmation_body',
				size: '',
				title: utils.plural(oConfig.labels.savedCartsLabels.itemText, details, true) + ' ' + oConfig.labels.savedCartsLabels.modalConfirmationHeader
			} :
			{
				body: 'catalog.atc_body',
				footer: 'catalog.atc_popup_buttons',
				size: getATCModalSize(),
				title: utils.plural(' Product', details, true) + ' Added to Cart'
			};

			runHook('modalATCAfterConfiguration', { self: self, cart: cart, modalConfig: modalConfig, details: details });

			utils.openModal(modalConfig, data);
		}

		utils.renderTemplateToContainer = function (template, data) {
			var surrogate = document.createElement('div');
			var $container = $('<div>').append(surrogate);

			ko.renderTemplate(
				template,
				data,
				null,
				surrogate,
				'replaceNode'
			);

			return $container;
		};

		utils.getSavedCart = function (carts, callback) {
			var selectedCart = ko.observable();
			selectedCart.subscribe(callback);

			var data = { savedCarts: carts, selectedCart: selectedCart };
			utils.openModal({
				body: oConfig.savedCartPopupTemplate,
				size: 'small',
				title: oConfig.labels.savedCartsLabels.modalHeader,
				backdrop: 'static'
			}, data);
		};

		utils.createGuid = function () {
			// https://stackoverflow.com/a/8809472
			var d = new Date().getTime();
			if(window.performance && typeof window.performance.now === "function"){
				d += performance.now(); //use high-precision timer if available
			}
			var guid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
				var r = (d + Math.random()*16)%16 | 0;
				d = Math.floor(d/16);
				return (c=='x' ? r : (r&0x3|0x8)).toString(16);
			});
			return guid.toUpperCase();
		};

		// Generates a unique ID and returns it twice in a row. Intended for use with the `for`
		// attribute on `label` elements.
		(function () {
			var previousId;

			utils.labelId = function () {
				var id = previousId || utils.createGuid();
				previousId = previousId ? null : id;
				return id;
			};
		}());

		utils.openModal = function (options, data) {
			_.forEach(['header', 'body', 'footer'], function (prop) {
				if (options[prop]) {
					options[prop] = utils.renderTemplateToContainer(options[prop], data);
				}
			});
			modal.open(options);
		};

		var productModel = function (product) {
			var self = this;

			var productCollectionMapping = {
				create: function (options) {
					return new productModel(options.data);
				}
			}

			ko.mapping.fromJS(product, {
				copy: [
					'tab2_html',
					'opt1',
					'opt2',
					'opt3',
					'opt4',
					'opt5',
					'opt6',
					'opt7',
					'opt8',
					'opt9',
					'accountHistory',
					'reviews',
					'tabs',
					'type',
					'promoDescriptions',
					'configuratorEditData',
					'calc_inv_message',
					'use_cart_options',
					'showAddOns',
					'addOnLabel',
					'addOnDisplay'
				],
				related: productCollectionMapping,
				secondRelated: productCollectionMapping,
				children: productCollectionMapping,
				alsoBought: productCollectionMapping,
				addOns: productCollectionMapping
			}, self);

			self.children.extend({ deferred: true });

			self.atcButtonText = ko.observable('');
			self.atcErrorText = ko.observable('');

			if(utils.getParameter('quickadd') == 'true' && self.type === 'parent'){
				self.childDisplayType('droplist');
			}

			self.updateAtcButtonText = function() {
				if(self.configuratorEditData && self.configuratorEditData.od_id) {
					self.atcButtonText(oConfig.labels.updateCartItem || 'Update');
				} else if (utils.isActiveQuote) {
					self.atcButtonText('Add To ' + oConfig.labels.savedCarts);
				} else {
					self.atcButtonText(oConfig.labels.addToCart || 'Add');
				}
			};

			self.updateAtcButtonText();

			self.hasCartOptions = ko.computed(function() {
				if(self.questions && self.questions() && self.questions().length && (self.type === 'parent' || self.useCartOptions())) {
					return true;
				} else {
					if(self.children && self.children().length) {
						return self.children().reduce(function(hasQuestions, child) {
							return hasQuestions || (!!child.questions && !!child.questions() && !!child.questions().length && child.useCartOptions());
						}, false);
					} else {
						return false;
					}
				}
			});

			self.requireInfoForAtc = ko.computed(function () {
				return !!(
						self.childDisplayType() || 
						self.useConfigurator() || 
						self.hasCartOptions() ||
						(self.showAddOns && oConfig.detailConfig.useAddOnProducts && oConfig.searchConfig.requireAddOnSelection)
					) && oConfig.pageName == 'pc_combined_results.asp';
			});

			self.priceDisplay = ko.observable(function () {
				var template = 'catalog.details_link';
				if(oConfig.pageName == 'pc_product_detail.asp'){
					template = 'catalog.selected_product_price_display';
				}else if (self.useConfigurator()){
					template = 'catalog.configurator_price_display';
				}else if (self.requireInfoForAtc() && self.childStartingPrice()) {
					template = 'catalog.price_start_at'
				} else if (!self.requireInfoForAtc()) {
					template = 'catalog.selected_product_price_display';
				}

				//Manually check for template overrides since this is dynamically returned.
				//Need to convert this to a function and use any time template names are returned.
				if(document.getElementById(template + '_custom')){
					return template + '_custom';
				}else{
					return template;
				}

			}());

			self.selectedQty = ko.observable(function() {
				if(self.configuratorEditData) {
					return self.configuratorEditData.qty;
				}else if(self.qty){
					return self.qty;
				} else {
					return undefined;
				}
			}());

			self.isQtyValid = ko.observable(true);

			self.selectedWarehouse = ko.observable(_.find(self.inventory.warehouses(), function(wh){ return wh.isDefault() } ) || [] );

			if(self.configuratorEditData && self.configuratorEditData.pw_id) {
				self.selectedWarehouse(_.find(self.inventory.warehouses(), function(wh){ return wh.key() == self.configuratorEditData.pw_id } ) || [] );
			}

			self.selectedUom = ko.observable(
				(function () {
					var uom = undefined;

					// It's possible that this is a parent product and the configurator
					// edit data will not match a uom on the parent, however the selectedProduct
					// has not been set at this point, so we can't just use selectedProduct
					// With the previous version of this code, this would make the selectedUom
					// undefined and break other parts of the code because it skipped all other
					// checks if configuratorEditData had a uom value. Now it will check the
					// other conditions if the configuratorEditData doesn't match an available uom.
					// There's certainly a better way to handle this, but this will do for now.
					if(self.configuratorEditData && self.configuratorEditData.uom) {
						uom = _.find(self.uomPrice(), function (price) {
							return price.description() == self.configuratorEditData.uom;
						});
					}

					if(!uom) {
						uom = _.find(self.uomPrice(), function (price) {
							if (price.hasOwnProperty("isDefault")){
								return price.isDefault(); //set from SSJS
							} else if(typeof price.IsDefault() === "undefined"){
								return price.ConversionRate() === 1; //fallback
							} else{
								return price.IsDefault() || price.ConversionRate() === 1 || price.ConversionRate() === 12; //returned from COM
							}
						});
					}

					if(!uom && self.uomPrice().length > 0) {
						//if still no match then take the first one
						uom = self.uomPrice()[0];
					}

					return uom;
				})());

			_.each(self.uomPrice(),function(uom){
				var bHasBreaks = false;
				bHasBreaks = uom.breaks().length > 0;
				uom.hasBreaks(bHasBreaks);
			});

			// Set the selected quantity back to the default if the UOM changes
			self.selectedUom.subscribe(function(newValue) {
				var defaultQty = newValue.minQty() || newValue.step() || 1;
				self.selectedQty(defaultQty);
			});

			self.processedBreaks = ko.computed(function() {
				if (!( self.selectedUom() && self.selectedUom().hasBreaks() )) {
					return [];
				}

				var processed = [];
				var data = self.selectedUom().breaks();

				//converted from price break popup window to properly display single breaks that actually have multiple break records
				if(data[data.length -1].qty() == '1000000' || data[data.length -1].qty() == '100000000'){
					data.pop();
				}

				//If there's only one break we will skip showing the price break information
				if(data.length == 1) {
					return [];
				}

				processed = data.map(function(lineBreak) {
					var price, startQ, endQ, range, qty, proceed;
					price = lineBreak.price();
					startQ = lineBreak.qty();
					endQ = lineBreak.qtyEnd();
					proceed = true;
					qty = self.selectedUom().uom_conversion() || 1;

					if(self.selectedUom().uom() == 'uom_sales' & qty > 1){
						startQ = Math.ceil(startQ / qty);
						endQ = ((Math.ceil(endQ / qty) * qty) - qty) / qty;
						if(qty >= startQ && (qty <= endQ || endQ != 0)){
							price = parseFloat(price).toFixed(2) * qty * startQ;
							if (endQ != '0' && parseInt(endQ) > 0) {
								range = startQ + ' - ' + endQ;
							} else {
								range = startQ + '+';
							}
						}else{
							proceed = false;
						}
					}else{
						if (endQ != '0') {
							range = startQ + ' - ' + endQ;
						} else {
							range = startQ + '+';
						}
					}
					if(proceed){
						return {
							price: price,
							range: range
						}
					}else{
						return {}
					}
				});
				return processed.filter( function(value){ return JSON.stringify(value) !== '{}'; });
			});


			self.configPrice = buildConfiguratorPriceObservable(self.key());

			self.unitPrice = ko.computed(function () {
				if(self.configuratorEditData && self.configuratorEditData.priceCalcType == 'fixed') {
					return self.configuratorEditData.price;
				}
				return self.selectedUom().price() + self.configPrice();
			});

			self.priceTrace = ko.computed(function() {
				var bPriceErrorMessage = '';
				if(utils.getParameter('action') == 'showpricetrace') {
					bPriceErrorMessage = 'Price trace is not available when using WSP Search Service';
				}
				return self.selectedUom().priceTrace
					? self.selectedUom().priceTrace()
					: bPriceErrorMessage;
			});


			self.youSavePercent = ko.computed(function () {
				return (((self.selectedUom().suggestedPrice() - self.selectedUom().price()) / self.selectedUom().suggestedPrice()) * 100).toFixed(2) + '%';
			});

			self.suggestedPrice = ko.computed(function () {
				return self.selectedUom().suggestedPrice();
			});

			self.showYouSave = ko.computed(function () {
				return parseFloat((self.selectedUom().suggestedPrice() || 0).toFixed(oConfig.detailConfig.globalUnitPriceDecimalPlaces)) > parseFloat((self.selectedUom().price() || 0).toFixed(oConfig.detailConfig.globalUnitPriceDecimalPlaces)) && self.selectedUom().suggestedPrice() > 0 && oConfig.showProdYouSave == 1;
			});

			self.childView = function () {
				// return (self.childDisplayType() || 'stand-alone') + '-layout';
				return 'stand-alone-layout';
			}();

			self.showAtc = function () {
				var primary1    = self.inventory.showAtc() && oConfig.searchConfig.showAtc && self.mapPriceType() !== 'show_message';
				var secondary1  = oConfig.isLoggedIn || self.mapPriceType() !== 'require_login_for_atc';
				var secondary2  = oConfig.isLoggedIn || self.mapPriceType() !== 'require_login_for_price_and_atc';
				var tertiary1   = self.mapPriceType() === 'require_atc' || (self.mapPriceType() === 'require_login_or_atc' && !oConfig.isLoggedIn);
				var tertiary2   = self.mapPriceType() !== 'hide' && (self.showProdAtc() != 0);
				var quaternary1 = !(self.type === 'parent' && self.childDisplayType() == 'droplist' && oConfig.pageName != 'pc_combined_results.asp')

				return primary1 &&
						(secondary1) &&
						(secondary2) && (
							(tertiary1) ||
							(tertiary2)
						)
						&& quaternary1;
			}();

			self.showQuickAtc = ko.computed(function () {
				var showQuickAtc = self.showAtc && !self.requireInfoForAtc() && self.type !== "parent"; //initial setting
				if(oConfig.showChildrenSelection && self.type === "child" ){
					if(self.unitPrice() > 0 && self.showAtc){
						showQuickAtc = true;
					}
					else{
						showQuickAtc = false;
					}
				}

				return showQuickAtc; //(self.showAtc && !self.requireInfoForAtc())
			});

			self.allowQuickAddModal = ko.computed(function() {
				if (oConfig.pageName == 'pc_product_detail.asp') return false;

				var exceptions = ['exploded-view', 'input-qty'];
				if (exceptions.includes(self.childDisplayType())) return false;

				return true;
			});

			self.isInCart = ko.computed(function(){
				var cartCount = 0;
				if(viewModel.activeCart && viewModel.activeCart().length){
					var product = _.filter(viewModel.activeCart(), function(cart){
						return cart.prod_key == self.key() || cart.parent_p_id == self.key();
					});
					cartCount = product.length;
				}
				return cartCount;
			});

			self.showPrice = function () {
				return self.type !== 'parent' && (
						(self.mapPriceType() !== 'show_message') &&
						!((self.mapPriceType() === 'require_login_for_price_and_atc') && !oConfig.isLoggedIn) &&
						!(self.mapPriceType() === 'require_atc' || (self.mapPriceType() === 'require_login_or_atc' && !oConfig.isLoggedIn))
					) &&
					(self.mapPriceType() !== 'hide') && (self.showProdPrice() != 0) &&
					oConfig.showPricingOrderEntry;
			}();

			self.showBreaks = ko.observable(function(){
				return oConfig.useBreaks && oConfig.useBreaksTable && oConfig.pageName == 'pc_product_detail.asp';
			}());

			self.mapPriceMessage = function () {
				if (self.mapPriceType() === 'show_message') {
					return oConfig.mapBehaviorMessages.showMessage;
				} else if (self.mapPriceType() === 'require_login_for_price_and_atc' && !oConfig.isLoggedIn) {
					return oConfig.mapBehaviorMessages.requireLoginMessage;
				} else if (self.mapPriceType() === 'require_login_for_atc' && !oConfig.isLoggedIn) {
					return oConfig.mapBehaviorMessages.requireLoginAtcMessage;
				} else if (self.mapPriceType() === 'require_atc') {
					return oConfig.mapBehaviorMessages.requireAtcMessage;
				} else if (self.mapPriceType() === 'require_login_or_atc' && !oConfig.isLoggedIn) {
					return oConfig.mapBehaviorMessages.requireLoginOrAtcMessage;
				} else if (self.mapPriceType() !== 'hide') {
					return '';
				}
			}();

			self.warehouseTemplate = function () {
				if (oConfig.showWarehouses && self.inventory.warehouses().length > 0 && self.inventory.inventoryStatus() === 'in') {
					if ((oConfig.allowWarehouseSelection && (oConfig.pageName == 'pc_combined_results.asp' && oConfig.searchConfig.hideAtcShowInv)) || (oConfig.allowWarehouseSelection && self.showQuickAtc())) {
						return 'warehouse_droplist';
					} else if (oConfig.useWarehousesTable) {
						return 'warehouse_table';
					} else {
						return 'warehouse_info';
					}
				} else {
					return 'warehouse_off';
				}
			}();

			self.priceBreaksTemplate = function(){
				if(oConfig.useBreaks){
					if(oConfig.useBreaksTable && oConfig.pageName == 'pc_product_detail.asp'){
						return 'catalog.qty_breaks_table';
					}else{
						return 'catalog.qty_breaks';
					}
				}else{
					return 'catalog.breaks_off';
				}
			}();

			self.uomTemplate = ko.computed(function() {
				var template;
				if (self.selectedProduct().uomPrice().length > 1) {
					template = 'catalog.uom_select';
				} else {
					template = 'catalog.uom_input';
				}

				if(document.getElementById(template + '_custom')){
					return template + '_custom';
				}else{
					return template;
				}
			});

			self.documentsTemplate = function () {
				return 'catalog.documents';
			}();

			self.qtyInputClick = function (key) {
				jQuery('#qty_'+key).focus();
				jQuery('#qty_'+key).select();
			};

			self.validateQtyInput = function (data) {
				if (utils.getCookie('productLayout') === 'list') {
					return '';
				} else {
					return '1';
				}
			};

			self.hideOnListView = function () {
				if ((isActiveLayout('list') && !oConfig.detailConfig.productKey ) || (self.type === 'child' && oConfig.detailConfig.productKey)) {
					return 'hide';
				}
			};

			self.isChild = function () {
				if (self.type === 'child'){
					return true;
				}else{
					return false;
				}
			}

			self.isParent = function() {
				if (self.type.toLowerCase() === 'parent'){
					return true;
				}else{
					return false;
				}
			}

			self.minQty = ko.computed(function () {
				if (self.configuratorEditData && self.configuratorEditData.minQty) {
					self.selectedProduct().selectedUom().minQty(self.configuratorEditData.minQty);
				}
				if (oConfig.useMinimumQuantity) {
					return self.selectedProduct().selectedUom().minQty();
				} else {
					return 0;
				}
			});

			self.stepQty = ko.computed(function () {
				if (self.configuratorEditData && self.configuratorEditData.qtyIncrement) {
					self.selectedProduct().selectedUom().step(self.configuratorEditData.qtyIncrement);
				}
				if (oConfig.useQuantityIncrement) {
					return self.selectedProduct().selectedUom().step();
				} else {
					return 1;
				}
			});

			self.maxQty = ko.computed(function () {
				if (self.configuratorEditData && self.configuratorEditData.maxQty) {
					self.selectedProduct().selectedUom().maxQty(self.configuratorEditData.maxQty);
				}
				if (oConfig.useMaximumQuantity && self.selectedProduct().selectedUom().maxQty() > 0) {
					return self.selectedProduct().selectedUom().maxQty();
				} else {
					return '';
				}
			});

			self.hasQuantityRestrictions = ko.computed(function () {
				return (oConfig.useMinimumQuantity || oConfig.useMaximumQuantity || oConfig.useQuantityIncrement) && !!(self.minQty() || self.stepQty() !== 1 || self.maxQty());
			});

			self.quantityRestrictionsHtml = ko.computed(function () {
				var lines = [];

				if (self.minQty())
					lines.push(oConfig.labels.minQtyPopover.replace(/<min_qty>/,self.minQty()));

				if (self.stepQty() !== 1)
					lines.push('Qty Increment: ' + self.stepQty());

				if (self.maxQty())
					lines.push('Maximum Qty: ' + self.maxQty());

				return lines.join('<br>');
			});

			self.addToSavedCart = function () {
				utils.getSavedCart(viewModel.savedCarts(), function (cart) {
					if (cart) {
						if (!_.includes(viewModel.savedCarts(), cart)) {
							// Insert the new cart in sorted order, notifying exactly once.
							var index = _.sortedIndex(viewModel.savedCarts(), cart, 'nickname');
							viewModel.savedCarts.splice(index, 0, cart);
						}

						var parentKey;

						if(self.type == 'child' && viewModel.mainProduct) {
							parentKey = ko.unwrap(viewModel.mainProduct).key();
						}

						utils.addToCart(self, cart, parentKey);
					}
				});
			};

			self.addToCart = function () {
				var parentKey;

				if(self.type == 'child' && viewModel.mainProduct) {
					parentKey = ko.unwrap(viewModel.mainProduct).key();
				}

				return utils.addToCart(self, undefined, parentKey);
			};

			self.atcPopupSuccess = function () {

			};

			self.atcPopupFail = function () {

			};

			self.selectFirstTab = function () {
				$('#tab1 > a').click();
			};

			self.getWebPage = function (webPageId) {
				return 'page.asp?p_key=' + webPageId + ' .wpc_page_content';
			};

			self.useTabs = function () {
				return oConfig.detailConfig.useAdvancedTabs && self.tabs && self.tabs.length && self.showTabs();
			}

			self.usingDownloadsTab = function() {
				var index = _.findIndex(self.tabs, function(t) {
								return t.dynamicSource == "downloads"
							});
				return self.useTabs() && index > -1;
			}

			self.getSmartListLinkOrderStats = function(parent){
				if(!parent){
					return 'product_history_detail.asp'
				}
				if(oConfig.detailConfig.useSkuDisplay && oConfig.detailConfig.useAliases) {
					return 'product_history_detail.asp?search2=(searchexact~p.sku_display~' + parent.sku() + '|OR|searchexact~pa.sku_alias~' + parent.sku() + '&s=' + parent.sku()
				}
				else if(oConfig.detailConfig.useAliases){
					return 'product_history_detail.asp?search2=searchexact~pa.sku_alias~' + parent.sku() + '&s=' + parent.sku()
				}
				else if(oConfig.detailConfig.useSkuDisplay) {
					return 'product_history_detail.asp?search2=searchexact~p.sku_display~' + parent.sku() + '&s=' + parent.sku()
				}else{
					return 'product_history_detail.asp?search2=searchexact~p.sku~' + parent.sku() + '&s=' + parent.sku()
				}
			};

			self.getSmartListLinkInvoiceStats = function(parent){
				if(!parent){
					return 'products_invoiced_detail.asp'
				}
				if(oConfig.detailConfig.useSkuDisplay && oConfig.detailConfig.useAliases) {
					return 'products_invoiced_detail.asp?search2=(searchexact~p.sku_display~' + parent.sku()+ '|OR|searchexact~pa.sku_alias~' + parent.sku() + '&s=' + parent.sku()
				}
				else if(oConfig.detailConfig.useAliases){
					return 'products_invoiced_detail.asp?search2=searchexact~pa.sku_alias~' + parent.sku() + '&s=' + parent.sku()
				}
				else if(oConfig.detailConfig.useSkuDisplay) {
					return 'products_invoiced_detail.asp?search2=searchexact~p.sku_display~' + parent.sku() + '&s=' + parent.sku()
				}else{
					return 'products_invoiced_detail.asp?search2=searchexact~p.sku~' + parent.sku() + '&s=' + parent.sku()
				}
			};

			self.tableColumns = ko.computed( function () {
				var columns = Array.prototype.concat(
					[
						{
							if: oConfig.showImgCol,
							label: oConfig.labels.imgCol,
							field: 'thumb',
							template: 'catalog.input_qty_thumb_display',
							cellClass: 'qty-input-table-thumb'
						},
						{
							if: oConfig.showNameCol && self.childDisplayType() !== 'add-row',
							label: oConfig.labels.nameCol,
							field: 'nm',
							template: 'catalog.input_qty_nm_display'
						},
						{
							label: 'SKU',
							field: 'sku',
							template: 'catalog.input_qty_sku_display'
						},
						{
							if: self.hasCartOptions(),
							label: 'Options',
							field: 'questions',
							template: 'catalog.cart_options'
						}
					],
					self.childDisplayType() !== 'add-row' ? self.childSelectors() || [] : [],
					[
						{
							if: oConfig.usePromos,
							label: 'Promo',
							template: 'catalog.input_qty_promo_display'
						},
						{
							if: oConfig.useIdp,
							label: 'Status',
							template: _.property('warehouseTemplate')
						},
						{
							label: 'Price',
							headerClass: 'cell-right',
							cellClass: 'cell-right',
							field: 'unitPrice',
							format: utils.formatPrice,
							template: 'catalog.selected_product_price_display'
						},
						{
							label: 'Actions',
							headerClass: 'cell-right',
							cellClass: 'cell-right',
							template: 'catalog.atc_qty_input',
							width: '1%'
						}
					]
				);

				// diagram_number needs to be added to the child products using the pos field on the mapping table
				if (self.childDisplayType() == 'exploded-view') {
					columns.unshift({
						label: 'ID',
						field: 'diagramNumber'
					});
				}

				return _.filter(columns, function (column) {
					return !('if' in column) || ko.unwrap(column.if);
				});
			});

			self.reviews = new PagedArray(self.reviews, 3);

			self.setupQuestions = function() {
				self.questions().forEach(function(question) {
					question.answers = ko.observableArray();

					if(question.type() === 'select') {
						if(question.useSelectOne()) {
							question.answers.push({
								label: question.selectOneText(),
								value: ''
							});
						}

						if(question.answerList().length > 0) {
							var answersSplit = question.answerList().split('|');
							answersSplit.forEach(function(answer) {
								var answerSet = answer.split('~');
								question.answers.push(
									{
										label: answerSet[0],
										value: answerSet[0]
									});
							});
						}
					}
				});
			}

			self.rowCollection = ko.observableArray();

			self.addRows = function(numberOfRows) {
				numberOfRows = numberOfRows || 1;
				for(var i=0;i<numberOfRows;i++) {
					var row = {
						selectedChild: ko.observable(undefined)
					}
					//' Clone the children for the selector so that the child
					//' references across rows are not the same.
					row.children = self.children ?  self.children().map(
														function(item) {
															var jsChild = ko.mapping.toJS(item);
															var koChild = ko.mapping.fromJS(jsChild, productMapping);

															//' Add the currentParent back as the re-mapping rests it
															koChild.currentParent = ko.observable(self);

															//' Add a new property for the current row index
															//' to make it easier to remove the items
															//' We use a guid to ensure it's always consistent.
															koChild.rowKey = utils.createGuid();
															return koChild;
														})
												: [];
					self.rowCollection.push(row);
				}
			}

			self.setupAddRowView = function() {
				if(self.childDisplayType() === 'add-row') {
					self.addRows();
					if(!!oConfig.childSkuMatch) {
						var matchedChild = self.rowCollection()[0].children.filter(function(child) {
												return oConfig.childSkuMatch === child.sku();
											});

						if(matchedChild && matchedChild.length > 0){
							self.rowCollection()[0].selectedChild(
								matchedChild[0]
							);
						}
					}
				}
			}

			self.childSelectors = ko.observableArray([]);

			self.processChildren = function() {
				_.each(self.children(), function(child){
					child.promoDescriptions = [];
					_.each(self.promoDescriptions, function(promo){
						if(promo.targetKeys.indexOf(child.key()) > -1){
							child.promoDescriptions.push(promo);
						}
					});
					child.configuratorEditData = self.configuratorEditData;
					child.currentParent(self);
					child.updateAtcButtonText();
					child.setupQuestions();
				});

				_.forEach(self, function (value, key) {
					var keyString = String(key);
					var matched = keyString.match(/^opt(\d)$/);

					if (matched && value) {
						var selector = {};
						selector.field = matched[0];
						selector.label = value;
						// _.sortByAll has been absorbed into _.sortBy in lodash 4.0.0+
						var lodashSortBy = typeof(_.sortByAll) == 'function' ? _.sortByAll : _.sortBy;

						selector.options = lodashSortBy(
							_.uniq(
								_.map(self.children(), function (child) {
									var optXsort = (typeof(child[matched[0] + '_sort']) == 'function' ? child[matched[0] + '_sort']() : child[matched[0] + '_sort']) || 0;
									var optSort = (typeof(child[matched[0]]) == 'function' ? child[matched[0]]() : child[matched[0]]) || 0;

									var thisOpt = {
										option: child[matched[0]],
										sort: optXsort || optSort
									};

									runHook("selectorOptionsItemOverride", { key: key, option: thisOpt, product: child });

									return thisOpt;

								}),
								'option'
							),
							[ 'sort', 'option' ]
						);
						selector.selectedOption = ko.observable();
						if (oConfig.detailConfig.selectChildProductOnLoad) {
							selector.selectedOption(selector.options[0]);
						}

						var childSku = oConfig.childSkuMatch || (!!self.configuratorEditData ? self.configuratorEditData.sku : '') || '';

						if (childSku){
							var oChild = {};
							_.each(self.children(),function(child){
								if(childSku == child.sku()) {
									oChild = child;
									return false;
								}
							});
							_.each(selector.options,function(option){
								if(option.option == oChild[selector.field]){
									selector.selectedOption(option);
								}
							})
						}
						selector.showSelector = ko.observable(true);
						self.childSelectors.push(selector);
					}
				});

				self.selectedOptions = ko.computed(function () {
					return _.map(ko.unwrap(self.childSelectors), function (item) {
						var selection = { option: '', sort: '' };
						if (item.selectedOption()) {
							selection = item.selectedOption().option;
						}
						return { field: item.field, option: selection };
					});
				});

				self.selectedProduct = ko.computed(function () {
					var filter = {};
					_.forEach(self.selectedOptions(), function (option) {
						filter[option.field] = option.option;
					});
					var filteredChildren = _.filter(self.children(), filter);
					if (filteredChildren
						&& filteredChildren.length === 1
						&& self.childDisplayType() !== 'input-qty'
						&& self.childDisplayType() !== 'exploded-view'
						&& self.childDisplayType() !== 'matrix-all'
						&& self.childDisplayType() !== 'add-row'
						) {
							return filteredChildren[0];
					} else {
						return self;
					}
				});

				self.setupQuestions();
				self.setupAddRowView();
			}

			if (self.children && self.children().length) {
				self.processChildren();
			} else {
				self.selectedProduct = ko.observable(self);
			}

			self.loadNextSelector = function(optNumber, callback, asyncLoadOptions) {
				var selectedOpts = _.map(self.childSelectors().filter(function(selector) {return !!selector.selectedOption && !!selector.selectedOption();}), function(s) {
					return s.selectedOption().option;
				}).join('~');
				$.ajax({
					url: oConfig.pageName, //current page.
					data: {
						ajax: 'get-product-opts',
						key: self.key(),
						optFields: selectedOpts,
						modal: 1,
						modalaction: utils.getParameter("modalaction")
					},
					dataType: 'json',
					success: function(data) {
						var selector = self.childSelectors().find(function(selector) {
							return selector.field == 'opt' + optNumber;
						});

						if(!selector) {
							selector = {
								field: 'opt' + optNumber,
								label: self['opt' + optNumber],
								showSelector: ko.observable(oConfig.displayDroplistPlaceholdersForLazyLoad)
							}
							self.childSelectors.push(selector);
						}

						selector.index = optNumber;
						selector.options = data.map(function(o) {
							return {
								option: o.opt,
								sort: 0,
								count: o.count,
								pKey: o.p_key
							}
						});
						selector.loading = ko.observable(false);
						selector.selectedOption = ko.observable();
						selector.showSelector(oConfig.displayDroplistPlaceholdersForLazyLoad || !!selector.options.length);

						selector.selectedOption.subscribe(function(newValue) {
							//clear any selectors after this one
							self.childSelectors().forEach(function(s) {
								if(s.index > selector.index) {
									s.selectedOption(undefined);
									s.options.splice(0, s.options.length);
									s.selectedOption.notifySubscribers();
									s.showSelector(oConfig.displayDroplistPlaceholdersForLazyLoad);
								}
							});

							self.childSelectors.notifySubscribers();

							if(self.children) self.children.removeAll();
							// did we actually select something
							if (newValue) {
								selector.loading(true);
								var callback = function() {
									selector.loading(false);
								}
								if (selector.index < self.childSelectors().length) {
									self.loadNextSelector(selector.index + 1, callback, asyncLoadOptions);
								} else {
									//load the child
									if (asyncLoadOptions) asyncLoadOptions.done = true;
									self.loadChildProduct(newValue.pKey, callback);
								}
							}else{
								self.selectedProduct(self);
							}
						});
						self.childSelectors.notifySubscribers();
					},
					error: function() {
						utils.popToastrError('Error Loading List', 'There was an error loading the product drop list');
					},
					complete: function() {
						if (callback) callback();
						if (asyncLoadOptions) {
							var asyncLoadOptionsArray = asyncLoadOptions.getArray();
							var index = optNumber - 1;
							var option = self.childSelectors()[index];
							var availableOptions = option.options;
							var selectedOption = null;
							if (index < asyncLoadOptionsArray.length) {
								_.forEach(availableOptions, function (value, key) {
									if (value.option == asyncLoadOptionsArray[index]) selectedOption = value;
								});
							} else if (oConfig.detailConfig.selectChildProductOnLoad) {
								selectedOption = availableOptions[0];
							}
							option.selectedOption(selectedOption);
						}
					}
				})
			}

			self.loadChildProduct = function(pKey, callback) {
				$.ajax({
					url: oConfig.pageName, //current page.
					data: {
						ajax: 'get-child-product',
						key: pKey,
						parentKey: oConfig.mainProductKey,
						modal: 1,
						modalaction: utils.getParameter("modalaction"),
						action: utils.getParameter("action") == 'showpricetrace' ? 'showpricetrace' : ''
					},
					dataType: 'json',
					success: function(data) {
						var product = ko.mapping.fromJS(data.products[0], productMapping);
						product.type = "child";
						// self.children.push(product);
						if(self.questions && self.questions().length && product.useCartOptions() && !product.f_id()) {
							if(product.questions) {
								product.questions(ko.mapping.fromJS(ko.mapping.toJS(self.questions))());
							} else {
								product.questions = ko.observableArray(ko.mapping.fromJS(ko.mapping.toJS(self.questions))());
							}
						}
						product.setupQuestions();
						product.configuratorEditData = self.configuratorEditData;
						product.updateAtcButtonText();
						self.selectedProduct(product);
						runHook('productDetailLoadChildProductSuccess', { self: self, product: product });
					},
					error: function() {
						utils.popToastrError('Error Loading Product', 'There was an error loading the product');
					},
					complete: callback
				});
			}

			self.quantityRestrictionsHtml.subscribe(function(newValue) {
				var popoverElement = $('#pop-' + $.escapeSelector(self.sku().replace(/([^A-Za-z0-9[\]{}_.:-])\s?/g, '_')));
				if(popoverElement){
					var popoverData = popoverElement.data('popover');
					if (popoverData) {
						popoverData.options.content = newValue;
					}
				}
			});

			self.lazyLoadingInProgress = ko.observable(false);

			if (self.key() == oConfig.mainProductKey && self.type === 'parent' && self.children().length === 0 && getOriginalPageName() === 'pc_product_detail.asp' && self.childDisplayType() != 'droplist') {
				if (!runHook('productDetailGetChildProductsByParentKey', { self: self }, {}, this)) {
				self.lazyLoadingInProgress(true);
				$.ajax({
					url: oConfig.pageName, //current page.
					data: {
						ajax: 'get-child-products-by-parent-key',
						key: oConfig.mainProductKey,
						modal: 1,
						modalaction: utils.getParameter("modalaction")
					},
					dataType: 'json',
					success: function(data) {
						data.forEach(function(childProduct) {
							var product = ko.mapping.fromJS(childProduct, productMapping);
							product.type = "child";
							if(self.questions && self.questions().length && product.useCartOptions() && !product.f_id()) {
								if(product.questions) {
									product.questions(ko.mapping.fromJS(ko.mapping.toJS(self.questions))());
								} else {
									product.questions = ko.observableArray(ko.mapping.fromJS(ko.mapping.toJS(self.questions))());
								}
								//product.hasCartOptions(true);
							}
							product.configuratorEditData = self.configuratorEditData;
							product.updateAtcButtonText();
							//self.selectedProduct(product);
							self.children.push(product);
						});

						self.processChildren();
						/*
						if(self.childDisplayType() === 'matrix-all') {
							self.matrix(ko.unwrap(ko.mapping.fromJS(generateMatrixData(ko.mapping.toJS(self)))));
						}
                        */
						self.lazyLoadingInProgress(false);
					},
					error: function() {
						utils.popToastrError('Error Loading Product', 'There was an error loading the product');
					},
					complete: function() { self.lazyLoadingInProgress(false); }
				});
			}
			}

			/*
				This function generates the display data for parent products whose
				childDisplayType is 'matrix-all'. It returns a data structure that
				looks like this:

				[
					{
						label: <<Label of row>>,
						swatch: <<Either an HTML color without the # or blank. E.g. 00ff44>>,
						thumb: <<A thumbnail image link to display if the swatch is blank>>,
						cols: [
							{
								label: <<Label of column>>,
								product: <<This links to the product.children[x] data. When KO maps this, it will be its own self-contained ProductModel.>>
							},
							{
								... more columns
							}
						]
					},
					{
						... more rows
					}
				]
			*/
			
			self.matrix = ko.computed(function () {
				if (self.childDisplayType() === 'matrix-all') {
					/***** Main method *****/

					// Initial vars
					var rowOpt = '';
					var colOpt = '';
					var swatchOpt = "color_code";

					// Build the matrix
					var rawChildren = self.children();
					var bucketed = bucketChildren(rawChildren, rowOpt, colOpt, swatchOpt);
					bucketed.rowKeys = sortKeys(bucketed.rowKeys);
					bucketed.colKeys = sortKeys(bucketed.colKeys);

					runHook('productDetailMatrixBeforeConstruction', {
						parent: self,
						configs: {
							rowOpt: rowOpt,
							colOpt: colOpt,
							swatchOpt: swatchOpt
						},
						bucketed: bucketed
					});

					var matrix = constructMatrix(bucketed);

					runHook('productDetailMatrixData', {
						parent: self,
						matrix: matrix
					});

					return matrix;
				} else {
					return [];
				}

				/***** Helper functions *****/

				// Find the unique row and column values and their sorts, and index the children.
				function bucketChildren(rawChildren, rowOpt, colOpt, swatchOpt) {
					var initial = {
						products: {},
						rowKeys: {},
						colKeys: {}
					};

					var result = _.reduce(rawChildren, function(acc, cur) {
						var rowLabel = ko.toJS(cur[rowOpt]);
						var rowSort = ko.toJS(cur[rowOpt + '_sort']);
						var rowSwatch = ko.toJS(cur[swatchOpt]);
						var rowThumb = ko.toJS(cur['thumb']);
						var colLabel = ko.toJS(cur[colOpt]);
						var colSort = ko.toJS(cur[colOpt + '_sort']);

						// Index the child
						if (!acc.products[rowLabel]) {
							acc.products[rowLabel] = {};
						}
						acc.products[rowLabel][colLabel] = cur;

						// Keep track of the unique row values
						if (!acc.rowKeys[rowLabel]) {
							acc.rowKeys[rowLabel] = {
								label: rowLabel,
								sort: rowSort,
								swatch: rowSwatch,
								thumb: rowThumb
							};
						}

						// Make sure we have a swatch and thumb
						if (!acc.rowKeys[rowLabel].swatch) {
							acc.rowKeys[rowLabel].swatch = rowSwatch;
						}
						if (!acc.rowKeys[rowLabel].thumb) {
							acc.rowKeys[rowLabel].thumb = rowThumb;
						}

						// Keep track of the unique column values
						acc.colKeys[colLabel] = {
							label: colLabel,
							sort: colSort
						};

						runHook('productDetailMatrixReduce', {
							parent: self,
							configs: {
								rowOpt: rowOpt,
								colOpt: colOpt,
								swatchOpt: swatchOpt
							},
							acc: acc,
							cur: cur
						});

						return acc;
					}, initial);

					runHook('productDetailMatrixBucketed', {
						parent: self,
						configs: {
							rowOpt: rowOpt,
							colOpt: colOpt,
							swatchOpt: swatchOpt
						},
						bucketed: bucketed
					});

					return result;
				}

				// Sort the rowKeys and colKeys
				function sortKeys(obj) {
					var list = _.values(obj);
					var sorted = _.sortBy(list, 'sort');
					return sorted;
				}

				function constructMatrix(bucketed) {
					// Construct the matrix, one row at a time
					var matrix = _.map(bucketed.rowKeys, function(row) {
						// Get values
						var label = row.label || '';
						var swatch = row.swatch || '';
						var thumb = row.thumb || 'images/no-image.png';

						// Generate the columns
						var cols = constructColumns(bucketed, row);

						// Return the results
						var row = {
							label: label,
							swatch: swatch,
							thumb: ko.observable(thumb), // Don't know why this is an observable, so leaving it
							cols: cols
						};

						runHook('productDetailMatrixRow', {
							parent: self,
							bucketed: bucketed,
							row: row
						});

						return row;
					});

					return matrix;
				}

				function constructColumns(bucketed, row) {
					var columns = _.map(bucketed.colKeys, function(col) {
						// Find the product that sits at the intersection of row and col
						var product = bucketed.products[row.label][col.label];

						var col = {
							label: col.label,
							product: product
						};

						runHook('productDetailMatrixCol', {
							parent: self,
							bucketed: bucketed,
							row: row,
							col: col
						});

						return col;
					});

					return columns;
				}
			}).extend({ deferred: true });

			if ((self.key() == oConfig.mainProductKey || oConfig.mainProductKey == '') && self.type !== 'parent') {
				self.setupQuestions();
			}

			// 2019-07-05 EJ - This only needs to run on the mainProduct on
			//                 the product detail page so I added a mainProductKey
			//                 var and check it against the current product's key
			if (self.key() == oConfig.mainProductKey && self.type === 'parent' && self.childSelectors().length === 0 && getOriginalPageName() === 'pc_product_detail.asp' && self.childDisplayType() == 'droplist') {

				if(!self.opt1 || self.opt1 == ''){
					//force this to stand-alone because it has bad data setup.
					self.type = 'stand-alone';
					console.log('This Parent product is set to "droplist" type but doesn\'t have a value in the opt1 field.  This is required for drop list type products.');
				}else{
					var selectorCount = 0;
					_.forEach(self, function (value, key) {
						var keyString = String(key);
						var matched = keyString.match(/^opt(\d)$/);

						if (matched && value) {
							selectorCount++;
							var selector = {};
							selector.field = matched[0];
							selector.label = value;
							selector.options = [];
							selector.selectedOption = ko.observable();
							selector.loading = ko.observable(matched[0] === 'opt1');
							selector.index = selectorCount;
							selector.showSelector = ko.observable(oConfig.displayDroplistPlaceholdersForLazyLoad);

							self.childSelectors.push(selector);
						}
					});

					// as third option:
					//   pass an array of options to do loading
					//   pass a shorter array to load up to that point then load first option from then on
					//   pass null/false to not do loading
					self.loadNextSelector(1, null, new (function() { // this is an inplace constructor
						this.array = oConfig.childOptionList,
						this.done = false;
						this.getArray = function() {
							if (this.done) return [];
							else return this.array;
						}
					})());
				}
			}

			self.removeRow = function(rowKey) {
				var index = _.findIndex(self.rowCollection(), function(row) {
					return row.selectedChild().rowKey === rowKey;
				});

				self.rowCollection.splice(index, 1);
			}

			self.currentParent = ko.observable(function() {
				if(self.type !== 'child') {
					return self;
				}

				if (self.currentparent && self.currentParent()) {
					return self.currentParent
				}

				if (self.type === 'child' && viewModel && ko.unwrap(viewModel.mainProduct)) {
					var matchingParent = self.parents().find(
						function(parent) {
							return parent.key() === ko.unwrap(viewModel.mainProduct).key();
						}
					)
					return matchingParent ? ko.unwrap(viewModel.mainProduct) : self;
				}

				return self;
			}());

			self.addRowsToCart = function() {
				var items = self.rowCollection().map(
													function(item) {
														return item.selectedChild();
													})
													.filter(
															function(item) {
																return item !== undefined
															});

				utils.addToCart(items, undefined, self.key(), true);
			}

			self.rowsAtcAttempted = ko.observable(false);

			self.questionsHaveValidAnswers = ko.computed(function() {
				var validOptions = true;

				if(self.useCartOptions()) {
					self.questions().some(function(question) {
						var answer = question.selectedAnswer();
						var answerPopulated = (answer !== '' && answer !== undefined);
						if(question.required() && !answerPopulated) {
							validOptions = false;
						}
						return !validOptions;
					});
				}

				return validOptions;
			});

			self.allRowsValid = ko.computed(function() {
				var rowsValid = true;

				self.rowCollection().some(function(row) {
					rowsValid = row.selectedChild() === undefined || row.selectedChild().questionsHaveValidAnswers();
					return !rowsValid;
				});

				return rowsValid;
			});

			// List of fields that will have legitimate HTML in them. Note - we
			// are intentionally not putting these in a site option in order to
			// force any changes to go through source control.
			var fieldsToDecode = [
				'inventory.stockMessage',
				'description',
				'name',
				'tabs>staticContent',
				'thumbAltText',
				'picAltText',
				'addOnLabel'
			];

			runHook('fieldsToDecodeFilter', { self: self, product: product, fieldsToDecode: fieldsToDecode });

   			// Set each field in the above list to the decoded version of itself
            fieldsToDecode.forEach(function(propName) {
                //using a > to denote a property on an array.
                if(propName.indexOf('>') > -1){
                    //get the array and the property on that array to be decoded
                    var collection = self[propName.split('>')[0]];
                    var propName = propName.split('>')[1];

                    //now check to see if the array is observable before looping
                    if(typeof collection == 'function'){
                        _.each(collection(), function(obj){
                            if (typeof obj()[propName] == 'function') { // If it is an observable
                                obj()[propName](utils.decodeHTML(obj()[propName]()) );
                            } else if (typeof obj()[propName] == 'string') { // If it is a string
                                obj()[propName] = utils.decodeHTML(obj()[propName]);
                            } else {
                                // Do nothing
                            }
                        })
                    }else{
                        _.each(collection, function(obj){
                            if (typeof obj[propName] == 'function') { // If it is an observable
                                obj[propName](utils.decodeHTML(obj[propName]()) );
                            } else if (typeof obj[propName] == 'string') { // If it is a string
                                obj[propName] = utils.decodeHTML(obj[propName]);
                            } else {
                                // Do nothing
                            }
                        })
                    }

                }else{
                    var field = _.get(self, propName);

                    if (typeof field == 'function') { // If it is an observable
                        field( utils.decodeHTML(field()) );
                    } else if (typeof field == 'string') { // If it is a string
                        _.set(self, propName, utils.decodeHTML(field));
                    } else {
                        // Do nothing
                    }
                }
            });

			if(self.currentParent()) {

				if(self.documents().length == 0 && self.currentParent().documents().length > 0 ){
					self.documents(self.currentParent().documents());
				}

				if(!self.description() && self.currentParent().description()) {
					self.description(self.currentParent().description())
				}

				//Handle Tab Inheritance at the individual tab instead of the array of tabs
				var newTabs = [];
				for(i=1; i <= oConfig.detailConfig.numberOfProductTabs; i++){
					var parentTab = _.filter(self.currentParent().tabs, function(tab){ return tab.index == i})[0];
					var childTab  = _.filter(self.tabs,                 function(tab){ return tab.index == i})[0];
					if(childTab){
						newTabs.push(childTab);
					}else if(!childTab && parentTab){
						//Inherit from the parent
						newTabs.push(parentTab);
					}
				}
				if(newTabs){
					self.tabs = newTabs;
				}

			}

			if (self.showAddOns)  {
				if (self.addOnDisplay == 'checkboxes')
					self.selectedAddOns = ko.observableArray([]);
				else //             ^ note difference in plural
					self.selectedAddOn  = ko.observable();
			}

			self.addOnOptions = function(){
				var options = [];
				
				if(self.addOns){
					options = _.map(self.addOns(), function(product){
						product.selectedQty(product.minQty() || 1);
						return ko.observable(product)
					})
				}
				return options;
			}();

			runHook('productModelBottom', { self: self, product: product });
		};

		var productMapping = {
			create: function (options) {
				return new productModel(options.data);
			}
		};

		var searchResultsPropertiesModel = function (properties) {
			var self = this;

			self.selectedSort = ko.observable(utils.getParameter('sortby') || oConfig.searchConfig.defaultSort);
			self.selectedRpp = ko.observable(utils.getParameter('rpp') || oConfig.searchConfig.rpp);
			self.startCount = ko.observable((oConfig.searchConfig.page - 1) * oConfig.searchConfig.rpp + 1);

			self.endCount = ko.observable(function () {
				var rpp = (oConfig.searchConfig.rpp === 0) ? oConfig.searchConfig.total : oConfig.searchConfig.rpp;
				return Math.min(((oConfig.searchConfig.page - 1) * rpp) + rpp, oConfig.searchConfig.total);
			}());

			self.maxPage = ko.observable(
				Math.ceil(oConfig.searchConfig.total / oConfig.searchConfig.rpp)
			);

			self.selectedLayout = ko.observable(
				utils.getCookie('productLayout')
			);

			self.changeRpp = function (value) {
				var sUrl = utils.setParameter('rpp', value);
				sUrl = sUrl + '&page=1';
				window.location =  sUrl;
			};

			self.layoutTemplate = ko.computed(function () {
				utils.setCookie('productLayout', self.selectedLayout());
				window.location.reload();
				return 'catalog.' + self.selectedLayout() + '_view'
			});

			runHook('searchResultsPropertiesModelBottom', { self: self, properties: properties });
		};

		function PagedArray(array, pageSize) {
			//' if array has already been processed, just return it
			if(array && array.all) {
				return array;
			}
			var self = this;
			self.all = ko.observableArray(array || []);
			self.pageSize = ko.observable(pageSize || 10);
			self.page = ko.observable(1).extend({ counter: 1 });
			self.numPages = ko.computed(function () {
				return Math.ceil(self.size() / self.pageSize());
			});
			self.size = ko.computed(function () {
				return self.all().length;
			});
			self.items = ko.computed(function () {
				var pageSize = self.pageSize();
				var start = (self.page() - 1) * pageSize;
				return self.all.slice(start, start + pageSize);
			});
		}
	</script>



		<script type="text/html" id="catalog.breadcrumbs">
			<ul id="detail_breadcrumbs" class="breadcrumb" itemprop="breadcrumb" vocab="http://schema.org/" typeof="BreadcrumbList">
				<!-- ko if: oConfig.activeBreadcrumb && oConfig.activeBreadcrumb.length > 0 -->
					<!-- ko foreach: oConfig.activeBreadcrumb -->
						<li data-bind="css: { active: !link }, attr: {'property': utils.breadCrumbProperty(link), 'typeof': utils.breadCrumbItemType(link)} ">
							<!-- ko if: link -->
								<a property="item" typeof="WebPage" data-bind="attr: { href: link }"><span data-bind="html: name" property="name"></span></a>
								<span class="divider"></span>
							<!-- /ko -->
							<span data-bind="html: link ? '' : utils.decodeHTML(name) "></span>
							<meta property="position" data-bind="attr: { 'content' : $index() + 1 }">
						</li>
					<!-- /ko -->
				<!-- /ko -->
				<!-- ko ifnot: oConfig.activeBreadcrumb && oConfig.activeBreadcrumb.length > 0 -->
					<!-- ko foreach: $data -->
						<li data-bind="css: { active: !link }, attr: {'property': utils.breadCrumbProperty(link), 'typeof': utils.breadCrumbItemType(link)} ">
							<!-- ko if: link -->
								<a property="item" typeof="WebPage" data-bind="attr: { href: link }"><span data-bind="html: name" property="name"></span></a>
								<span class="divider"></span>
							<!-- /ko -->
							<span data-bind="html: link ? '' : utils.decodeHTML(name) "></span>
							<meta property="position" data-bind="attr: { 'content' : $index() + 1 }">
						</li>
					<!-- /ko -->
				<!-- /ko -->
			</ul>
		</script>

	
		<script type="text/html" id="catalog.detail">
			<!-- ko if: mainProduct.selectedProduct -->
				<div id="detail_page_product">
					<span data-bind="template: { name: 'catalog.breadcrumbs', data: breadcrumbs }"></span>
					<span data-bind="template: { name: mainProduct.childDisplayType() === 'input-qty' || mainProduct.childDisplayType() === 'exploded-view' || mainProduct.childDisplayType() === 'matrix-all' || mainProduct.childDisplayType() == 'add-row' ? 'catalog.advanced_parent_layout' : 'catalog.product_view', data: mainProduct }"></span>
					<span data-bind="template: { name: 'catalog.additional_sections', data: mainProduct }"></span>
				</div>
			<!-- /ko -->
			<!-- ko ifnot: viewModel.mainProduct.selectedProduct -->
				<div id="detail_page_product">
					<div class="alert alert-warning" data-bind="html: oConfig.labels.productNotFound"></div>
				</div>
			<!-- /ko -->

		</script>
	
		<script type="text/html" id="catalog.results">
			<!-- ko ifnot: oConfig.searchConfig.pageType == 'category' && !$data.category -->
				<div id="list_wrap">
					<div id="list_wrap_pad">
						<div id="list_head" data-bind="
							template: $data.category ?
							{ name: 'catalog.category_header', data: category } :
							'catalog.page_title'
						"></div>
						<div id="products_header" class="list-toolbar products_header" data-bind="template: 'catalog.header'"></div>
						<div id="products_view" data-bind="attr : { 'data-layout' : getActiveLayout() }, template: getLayoutTemplate($data)"></div>
						<div id="products_footer" class="list-toolbar products_footer" data-bind="template: { name : 'catalog.footer' } "></div>
					</div>
				</div>
			<!-- /ko -->
			<!-- ko if: oConfig.searchConfig.pageType == 'category' && !$data.category -->
				<div id="list_wrap">
					<div id="list_wrap_pad">
						<div class="alert alert-warning" data-bind="html: oConfig.labels.categoryNotFound"></div>
					</div>
				</div>
			<!-- /ko -->
		</script>



	<script type="text/html" id="catalog.category_header">
		<!-- ko template: { name: 'catalog.breadcrumbs', data: breadcrumbs } --><!-- /ko -->
		<!-- ko if: slideShowDisplay == 'above' -->
			<!-- ko template: { name: 'catalog.slideshow' } --><!-- /ko -->
		<!-- /ko -->
		<div class="head_container">
			<!-- ko if: pic -->
				<div class="head_thumb">
						<img data-bind="attr: { src: utils.buildImagePath(pic) }"/>
				</div>
			<!-- /ko -->
			<div class="head_desc_container">
				<h1 class="head_title" data-bind="html: name"></h1>
				<!-- ko if: oConfig.searchConfig.showCategoryDescription && description -->
					<div class="head_desc" data-bind="html: description"></div>
				<!-- /ko -->
			</div>
		</div>
		<!-- ko if: slideShowDisplay == 'below' -->
			<!-- ko template: { name: 'catalog.slideshow' } --><!-- /ko -->
		<!-- /ko -->
		<!-- ko template: { name: 'catalog.category_list', data: children, if: children.length > 0 } --><!-- /ko -->
	</script>

	<script type="text/html" id="catalog.category_list">
		<div class="category-listings" data-layout="gallery" data-bind="foreach: $data">
			<div class="prod-card">
				<div class="prod-thumb" data-bind="visible: oConfig.searchConfig.showThumb && pic2">
					<a data-bind="attr: { href: link, title: utils.decodeHTML(name), 'data-key': key }">
						<img data-bind="attr: { src: utils.buildImagePath(pic2) }"/>
					</a>
				</div>
				<div class="prod-info">
					<div class="prod-desc">
						<div class="prod-nm">
							<a data-bind="attr: { href: link, title: utils.decodeHTML(name), 'data-key': key }, html: name"></a>
						</div>
					</div>
				</div>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.page_title">
		<!-- ko if: oConfig.searchConfig.pageTitle == '' -->
			<h1 data-bind="
					text: oConfig.searchConfig.labels.searchResultsHeader
					        .replace('<count>', oConfig.searchConfig.total)
						      .replace('<keyword>', '&lsquo;' + decodeURIComponent(utils.getParameter('search_keyword')) + '&rsquo;'),
					visible: utils.getParameter('search_keyword').length > 0
					">
			</h1>
			<h1 data-bind="
					text: oConfig.searchConfig.total + ' results',
					visible: utils.getParameter('search_keyword').length === 0 && utils.getParameter('queue_id').length === 0
					">
			</h1>
		<!-- /ko -->
		<!-- ko if: oConfig.searchConfig.pageTitle != '' -->
			<h1 data-bind="html: oConfig.searchConfig.pageTitle"></h1>
		<!-- /ko -->
		<!-- ko if: viewModel.failedLookups && viewModel.failedLookups.length -->
			<div class="alert alert-warning">
				<p>The following SKUs could not be found or could not be added because they are no longer available:</p>
				<ul>
					<!-- ko foreach: viewModel.failedLookups-->
						<li data-bind="text: sku"></li>
					<!-- /ko -->
				</ul>
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.header">
		<div id="sort_control" class="list-toolbar-control sort-control" data-bind="template: 'catalog.order_by'"></div>
		<div id="rpp_control" class="list-toolbar-control rpp-control" data-bind="template: 'catalog.rpp'"></div>
		<div id="layout_control" class="list-toolbar-control layout-control" data-bind="template: 'catalog.layout'"></div>
	</script>

	<script type="text/html" id="catalog.order_by">
		<label class="input-prepend" data-bind="if: oConfig.searchConfig.showSort">
			<span class="add-on toolbar__sort-by__text" data-bind="html: oConfig.searchConfig.labels.sort"></span>
			<select
				id="page_sort"
                class="toolbar__sort-by__drop"
				data-bind="
					foreach: oConfig.searchConfig.productSortOptions,
					value: getSelectedSort(),
					event: { change: changeSort }
			">
				<option data-bind="text: display, attr: { value: field ? field + '~' + direction : '' }"></option>
			</select>
		</label>
	</script>

	<script type="text/html" id="catalog.rpp">
		<label class="input-append" data-bind="if: oConfig.searchConfig.showRpp, visible: !utils.getParameter('favorites')" >
			<select
				id="rpp"
                class="toolbar__per-page__drop"
				data-bind="
					options: oConfig.searchConfig.rppOptions,
					value: getSelectedRpp(),
					event: { change: changeRpp }
				">
				</select>
			<span class="add-on toolbar__per-page__text" data-bind="html: oConfig.searchConfig.labels.rpp" ></span>
		</label>
	</script>

	<script type="text/html" id="catalog.page_count">
		<div data-bind="text: 'Showing ' + getStartCount() + ' - ' + getEndCount() + ' of ' + oConfig.searchConfig.total + ' results'"></div>
	</script>

	<script type="text/html" id="catalog.layout">
		<div data-bind="if: oConfig.searchConfig.showLayout && !utils.getParameter('modal') && !utils.getParameter('queue_id')">
			<span data-bind="html: oConfig.searchConfig.labels.layout"></span>
			<div class="btn-group btn-group-small layout-control__wrap">
				<button
					type="button"
					id="gallery_layout_toggle"
					data-bind="
						click: function () { setLayout('gallery') },
						css: { active: isActiveLayout('gallery') },
						html: oConfig.searchConfig.labels.galleryView
					"
					class="btn btn-default"
				></button>
				<button
					type="button"
					id="list_layout_toggle"
					data-bind="
						click: function () { setLayout('list') },
						css: { active: isActiveLayout('list') },
						html: oConfig.searchConfig.labels.listView
					"
					class="btn btn-default"
				></button>
			</div>
			<div class="results-download" data-bind="template: { if: oConfig.searchConfig.showDownload && oConfig.isLoggedIn}">
				<a href='javascript: window.location = utils.pageUrl + (utils.pageUrl.indexOf("?")>0?"&":"?") + "downloadasfile=1";' class='cust_download' title='Download'>
					<img data-bind="attr: { src: utils.buildImagePath('common_images/ddt_download.png') }" border="0" align="absmiddle">
					Download
				</a>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.no_product_found">
		<div class="alert alert-warning">Product Not Found.</div>
	</script>

	<script type="text/html" id="catalog.no_results">
		<!-- ko if: oConfig.searchConfig.pageType == 'favlist' -->
			<p>There are no products in this favorites list.</p>
		<!-- /ko -->
		<!-- ko if: oConfig.searchConfig.pageType == 'invoice' -->
			<p class="alert alert-info">No items are eligible for reorder on invoice #<span data-bind="text: oConfig.searchConfig.reorderNumber"></span>. 
			Click <a href="invoices.asp">here</a> to choose a new invoice.</p>
		<!-- /ko -->
		<!-- ko if: oConfig.searchConfig.pageType == 'salesorder' -->
			<p class="alert alert-info">No items are eligible for reorder on sales order #<span data-bind="text: oConfig.searchConfig.reorderNumber"></span>. 
			Click <a href="all_orders.asp">here</a> to choose a new sales order.</p>
		<!-- /ko -->
		<!-- ko if: oConfig.searchConfig.pageType != 'category' && oConfig.searchConfig.pageType != 'favlist' 
		     && oConfig.searchConfig.pageType != 'invoice' && oConfig.searchConfig.pageType != 'salesorder' -->
			<!-- ko  if : oConfig.labels.noResults -->
				<span data-bind=" html : oConfig.labels.noResults "></span>
			<!-- /ko -->
			<!-- ko ifnot : oConfig.labels.noResults -->
				<p class="alert alert-info">There are no products that match your search.</p>
				<h5>Search Tips:</h5>
				<ul>
					<li>You may want to broaden your search. This can be accomplished by shortening or generalizing the words you use in your search.</li>
					<li>If you are entering a part number, do not include any hyphens or other punctuation marks. You may even try using a portion of the number if it is a long one.</li>
					<li>Spelling does makes a difference. Be sure to check for spelling errors as this will affect your results.</li>
					<li>Mutations of a word also make a difference. For example, the word 'accessory' will return different results than 'accessories'.</li>
					<li>Plural makes a difference too. Adding an 's' may impact results. Often it is better to search for the singular.</li>
					<li>The search is not case sensitive, so you can type in all lower case, all caps, or any mixture.</li>
					<li>Contact customer service for assistance if you still cannot find what you are looking for.</li>
				</ul>
			<!-- /ko -->
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.paging">
		<div
			class="pagination"
			data-bind="if: oConfig.searchConfig.rpp > 0 && oConfig.searchConfig.total > oConfig.searchConfig.rpp"
		>
			<ul data-bind="foreach: pagingNodes()">
				<li data-bind="css: { active: page == oConfig.searchConfig.page, disabled: !page }">
					<!-- ko if: page && page !== oConfig.searchConfig.page -->
						<a data-bind="attr: { 'href': utils.setParameter('page', page) }">
							<span data-bind="html: text"></span>
						</a>
					<!-- /ko -->
					<!-- ko ifnot: page && page !== oConfig.searchConfig.page -->
						<span data-bind="html: text"></span>
					<!-- /ko -->
				</li>
			</ul>
		</div>
	</script>

	<script type="text/html" id="catalog.footer">
		<div id="results_paging" class="list-toolbar-control" data-bind="template: 'catalog.paging'"></div>
		<div id="results_text" class="list-toolbar-control" data-bind="template: 'catalog.page_count'"></div>
	</script>


	<script type="text/html" id="catalog.gallery_view">
		<div
			id="prod_listings"
			class="prod-listings"
			data-bind="fastForEach: results"
		>
			<!-- ko template: 'catalog.product_card' -->
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.gallery_actions">
		<span data-bind="template: 'catalog.atc_full'"></span>
	</script>


	<script type="text/html" id="catalog.list_view">
		<form
			name="atc_form"
			id="atc_form"
			class="frmAddToCart"
			method="POST"
			data-bind="attr: { action: oConfig.formAction, submit: submitForm($data) }"
		>
			<div
				id="prod_listings"
				class="prod-listings"
				data-bind="fastForEach: results"
			>
				<!-- ko template: { name: 'catalog.product_card' } -->
				<!-- /ko -->
			</div>
			<!-- ko if: oConfig.searchConfig.showAtc && showAddAllToCart() && !oConfig.showListViewATC -->
				<div class="multi-add" data-bind="template: 'catalog.list_view_atc'"></div>
			<!-- /ko -->
		</form>
	</script>

	<script type="text/html" id="catalog.list_view_atc">
		<div class="multi-add__content" >
			<button
				class="btn btn-block btn-primary multi-add__btn"
				data-bind="
					html: utils.atcListButtonText(),
					click: function(data,event) {addToCartWithValidation(results(), event);}">
			</button>
		</div>
	</script>

<script type="text/html" id="catalog.product_card_with_children">
	<!-- ko template: 'catalog.product_card' --><!-- /ko -->
</script>


<script type="text/html" id="catalog.product_card_no_children">
	<!-- ko template: 'catalog.product_card' --><!-- /ko -->
</script>

<script type="text/html" id="catalog.product_card">
	<div class="prod-card">
		<!-- ko if: isActiveLayout('gallery') || oConfig.pageName == 'pc_product_detail.asp' -->
			<div class="prod-thumb" data-bind="visible: oConfig.searchConfig.showThumb, css: { '-using-flags': oConfig.usingFlags } ">
				<span class="prod-thumb-img" data-bind="template: 'catalog.image_link'"></span>
				<span class="prod-thumb-flags" data-bind="template: 'catalog.flags_thumb'"></span>
			</div>

			<div class="prod-info">
				<div class="prod-desc">
					<div class="prod-nm">
						<!-- ko template: 'catalog.name_link' --><!-- /ko -->
					</div>
					<!-- ko template: 'catalog.rating_score' --><!-- /ko -->
				</div>
				<div class="prod-idp" data-bind="template: 'catalog.inventory', visible: inventory.isInventoryItem() && oConfig.useIdp"></div>
				<!-- ko if: $data.isDangerous -->
					<!-- ko template: 'catalog.hazmat' --><!-- /ko -->
				<!-- /ko -->
				<!-- ko template: { name: 'catalog.product_account_history_short',data: accountHistory, if: accountHistory }--><!-- /ko -->
				<div class="prod-pricing" data-bind="template: { name: priceDisplay, data: selectedProduct } "></div>
				<!-- ko if: oConfig.showChildrenSelection && $data.children -->
					<div class="prod-children" data-bind= "template:{
						name: 'catalog.children_selection',
						if: oConfig.showChildrenSelection && $data.children && children().length
					}"></div>
				<!-- /ko -->
				<div class="prod-actions" data-bind="template: 'catalog.product_actions'"></div>
				<div class="prod-details">
					<!-- ko template: { name: 'catalog.detail_info' } --><!-- /ko -->
				</div>
				<!-- ko if: utils.getParameter('favorites') && oConfig.pageName == 'pc_combined_results.asp' -->
					<!-- ko template: 'catalog.remove_fav_button' --><!-- /ko -->
				<!-- /ko -->
			</div>
		<!-- /ko -->
		<!-- ko if: isActiveLayout('list') -->
			<div class="prod-thumb" data-bind="visible: oConfig.searchConfig.showThumb, css: { '-using-flags': oConfig.usingFlags } ">
				<span class="prod-thumb-img" data-bind="template: 'catalog.image_link'"></span>
				<span class="prod-thumb-flags" data-bind="template: 'catalog.flags_thumb'"></span>
			</div>
			<div class="prod-info">
				<div class="prod-desc">
					<div class="prod-nm">
						<!-- ko template: 'catalog.name_link' --><!-- /ko -->
					</div>
					<div class="prod-ds" data-bind="
						html: selectedProduct().description,
						visible: oConfig.searchConfig.showDescription && selectedProduct().description()">
					</div>
					<!-- ko template: 'catalog.rating_score' --><!-- /ko -->
					<div class="prod-details">
						<!-- ko template: { name: 'catalog.detail_info' } --><!-- /ko -->
					</div>
				</div>
			</div>
			<!-- ko template: { name: 'catalog.product_account_history_short',data: accountHistory, if: accountHistory }--><!-- /ko -->
			<div class="prod-atc">
				<div class="prod-idp" data-bind="template: 'catalog.inventory'"></div>
				<div class="prod-pricing" data-bind="template: { name: priceDisplay, data: selectedProduct } "></div>
				<!-- ko if: oConfig.showChildrenSelection && $data.children -->
					<div class="prod-children" data-bind= "template:{
						name: 'catalog.children_selection',
						if: oConfig.showChildrenSelection && $data.children && children().length
					}"></div>
				<!-- /ko -->
				<div class="prod-actions" data-bind="template: 'catalog.product_actions'"></div>
			</div>
			<!-- ko if: utils.getParameter('favorites') && oConfig.pageName == 'pc_combined_results.asp' -->
				<!-- ko template: 'catalog.remove_fav_button' --><!-- /ko -->
			<!-- /ko -->
		<!-- /ko -->
	</div>
</script>

<script type="text/html" id="catalog.advanced_parent_layout">
	<!-- ko template: { name: "catalog.product_title", data: selectedProduct } --><!-- /ko -->
	<div id="product_view" class="product_view" data-bind="attr: { class: oConfig.detailConfig.gridRowClass }">
		<div data-bind="attr: { class: oConfig.detailConfig.gridLeftColumnClass + ' product-detail__left' }">
				<div id="product_images" data-bind="template: { name: 'catalog.image_gallery', data: selectedProduct }"></div>
		</div>
		<div data-bind="attr: { class: oConfig.detailConfig.gridRightColumnClass + ' product-detail__right' }">
			<div class="product_view__share-code" data-bind="template: 'catalog.share_code'"></div>
			<span class="product_view__detail-info" data-bind="template: 'catalog.detail_info'" ></span>
			<span class="product_view__rating-detail" data-bind="template: 'catalog.rating_detail'"></span>
			<div data-bind="
				template: {
					name: 'promotions.descriptions',
					if: promoDescriptions.length,
					data: {
						title: 'Product on Promotion',
						descriptions: promoDescriptions,
						selectedProduct: selectedProduct
					}
				}
			">
			</div>
			<div class="detail-docs" data-bind="template: { if: oConfig.detailConfig.showDocuments && !selectedProduct().usingDownloadsTab(), name: 'catalog.documents', data: documents() }"></div>
			<!-- ko if: oConfig.detailConfig.showProductDescriptionTop -->
				<span data-bind="template: { name: 'catalog.product_description', data: selectedProduct }"></span>
			<!-- /ko -->
			<a class="btn btn-primary scroll-to"
				 data-bind="
				   attr: { href: '#input-qty' },
					 html : oConfig.detailConfig.labels.inputQtyATCLabel,
					 click: function() {
						 scrollToTarget($element);
						 return false;
					 }
				">
			</a>
		</div>
	</div>
	<!-- ko template: 'catalog.additional_info' --><!-- /ko -->
	<span data-bind="template: { name: 'catalog.add_ons', data: selectedProduct }"></span>
	<h2 id="input-qty" data-bind="html : oConfig.detailConfig.labels.inputQty"></h2>
	<div id="atcform" data-bind="visible: !lazyLoadingInProgress(), template: childDisplayType() === 'matrix-all' ? 'catalog.matrix_form' : childDisplayType() === 'add-row' ? 'catalog.add_row_form' : 'catalog.input_qty_form'"></div>
	<div data-bind="if: lazyLoadingInProgress">
		<div class="sk-three-bounce" style="margin: 0 auto;">
			<div class="sk-child sk-bounce1"></div>
			<div class="sk-child sk-bounce2"></div>
			<div class="sk-child sk-bounce3"></div>
		</div>
		<div class="text-center">
			<small><em>Loading options...</em></small>
		</div>
	</div>

</script>

<script type="text/html" id="catalog.matrix_form">
	<form id="atc_form">
		<!-- ko template: 'catalog.matrix_table' --><!-- /ko -->

		<div class="form-actions">
			<button
				name="btnAddToCart"
				type="submit"
				class="btn btn-primary"
				data-bind="
					click: function (data, event) {
						var isSelected = _.flow(_.property('selectedQty'), ko.unwrap);
						var products = _.filter(children(), isSelected);
						addToCartWithValidation(products, event);
					},
					html : utils.atcListButtonText()
				"
			></button>
		</div>
	</form>
</script>

<script type="text/html" id="catalog.matrix_table">
	<div class="cim-matrix" data-bind="fastForEach: matrix">
		<div data-bind="template: 'catalog.matrix_row', css: 'cim-matrix__option cim-matrix__option-' + $index()"></div>
	</div><!-- .cim-matrix -->
</script>

<script type="text/html" id="catalog.matrix_row">
	<div class="cim-matrix__child__preview">
		<div class="cim-matrix__child__preview__wrap">
			<!-- ko if: swatch -->
				<div class="cim-matrix__child__preview__thumb" data-bind="style: { 'background-color': '#' + swatch() }"></div>
			<!-- /ko -->

			<!-- ko ifnot: swatch -->
				<div class="cim-matrix__child__preview__thumb">
					<img data-bind="attr: { src: utils.buildImagePath(thumb()) }" onerror="utils.handleImageError(this)">
				</div>
			<!-- /ko -->

			<h3 class="cim-matrix__child__preview__name"  data-bind="text: label"></h3>
		</div>
	</div><!-- cim-matrix__child__preview -->

	<div class="cim-matrix__children">
		<div class="cim-matrix__children__wrap" data-bind="fastForEach: cols">
			<div class="cim-matrix__child" data-bind="template: 'catalog.matrix_row_column'"></div>
		</div>
	</div><!-- .cim-matrix__children -->
</script>

<script type="text/html" id="catalog.matrix_row_column">
	<div class="cim-matrix__child__outer-wrap">
		<div class="cim-matrix__child__inner-wrap">
			<!-- ko if: product -->
				<p class="cim-matrix__child__size" data-bind="text: label"></p>
				<!-- ko template: { name: 'catalog.matrix_prod', data: product} --><!-- /ko -->
			<!-- /ko -->

			<!-- ko ifnot: product -->
				<!-- ko template: 'catalog.matrix_prod_not_found' --><!-- /ko -->
			<!-- /ko -->
		</div>
	</div><!-- /.cim-matrix__child -->
</script>

<script type="text/html" id="catalog.matrix_prod">
	<div class="cim-matrix__child__found">
		<div class="cim-matrix__child__pricing" data-bind="template: 'catalog.selected_product_price_display'"></div>
		<div class="cim-matrix__child__qty-input">
			<span data-bind="template: {name: 'catalog.atc_qty_input' }" ></span>
		</div>
		<div class="cim-matrix__child__idp">
			<p class="cim-matrix__child__idp-stock" data-bind="text: inventory.stock"></p>
			<p class="cim-matrix__child__idp-stock-msg" data-bind="html: inventory.stockMessage"></p>
		</div>
		<p class="cim-matrix__child__qty-price" data-bind="template: {name: priceBreaksTemplate }" ></p>
	</div>
</script>

<script type="text/html" id="catalog.matrix_prod_not_found">
	<div class="cim-matrix__child__not-found"><p> - </p></div>
</script>

<script type="text/html" id="catalog.input_qty_form">
	<form id="atc_form">
		<!-- ko template: 'catalog.input_qty_table' --><!-- /ko -->
		<!-- ko if: !oConfig.showListViewATC -->
			<div class="form-actions">
				<button
					name="btnAddToCart"
					type="submit"
					class="btn btn-large btn-block btn-primary"
					data-bind="
						click: function (data, event) {
							var isSelected = _.flow(_.property('selectedQty'), ko.unwrap);
							var products = _.filter(children(), isSelected);
							addToCartWithValidation(products, event, key());
						},
						html : utils.atcListButtonText()
					"
				></button>
			</div>
		<!-- /ko -->
	</form>
</script>

<script type="text/html" id="catalog.cart_options">
	<!-- ko if: oConfig.useCartOptions && hasCartOptions() -->
	<ul class="unstyled" data-bind="foreach: questions">
		<li class="form-inline" data-bind="template: { name: 'catalog.cart_option_' + type() }"></li>
	</ul>
	<!-- /ko -->
	<!-- ko if: oConfig.useCartOptions && !hasCartOptions()  -->
		<span class="mute">No options available</span>
	<!-- /ko -->
</script>

<script type="text/html" id="catalog.cart_option_textbox">
	<div class="control-group">
		<label class="control-label" data-bind="text: questionText"></label>
		<div class="controls">
			<input style="min-width: 180px !important /* temp fix for stretchy */;max-width: 80%;"
				data-bind="value: selectedAnswer,
				           attr: {required: required, maxlength: maxLength() == 0 ? '' : maxLength() },
									 init: function() { setSelectedCartOptionAnswer($data); }"
				type="text" />
			<span class="text-error" data-bind="text:requiredText, visible: required"></span>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.cart_option_textarea">
	<div class="control-group">
		<label class="control-label" data-bind="text: questionText"></label>
		<div class="controls">
			<textarea style="min-width: 180px !important /* temp fix for stretchy */;max-width: 80%;"
				data-bind="value: selectedAnswer,
				           attr: {required: required, maxlength: maxLength() == 0 ? '' : maxLength() },
									 init: function() { setSelectedCartOptionAnswer($data); }"></textarea>
			<span class="text-error" data-bind="text:requiredText, visible: required"></span>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.cart_option_select">
	<div class="control-group">
		<label class="control-label" data-bind="text: questionText"></label>
		<div class="controls">
			<select style="min-width: 162px !important /* temp fix for stretchy */;max-width: 80%;"
				data-bind="value: selectedAnswer,
				          attr: {required: required, maxlength: maxLength() == 0 ? '' : maxLength() },
									options: answers,
									optionsText: 'label',
									optionsValue: 'value',
									init: function() { setSelectedCartOptionAnswer($data); }">
				<option>-- Select One --</option>
			</select>
			<span class="text-error" data-bind="text:requiredText, visible: required"></span>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.add_row_form">
	<form id="atc_form" >
		<!-- ko template: 'catalog.add_row_table' --><!-- /ko -->
		<div class="text-error pull-right" data-bind="visible: !allRowsValid() && rowsAtcAttempted()">Please ensure all required fields are populated.</div>
		<div class="form-actions" data-bind="visible: !oConfig.childSkuMatch">
			<button class="btn btn-small" data-bind="click: function () { addRows(1) }"><i class="fas fa-fw fa-plus"></i> Add 1 Row</button>
			<button class="btn btn-small" data-bind="click: function () { addRows(5) }"><i class="fas fa-fw fa-plus"></i> Add 5 Rows</button>
			<button class="btn btn-primary pull-right" data-bind="click: addRowsToCart">Add To Cart</button>
		</div>
	</form>
	<!-- ko ifnot: showAtc -->
		<div data-bind="html: mapPriceMessage"></div>
	<!-- /ko -->
</script>

<script type="text/html" id="catalog.add_row_table">
	<div class="tablesaw-overflow qty-input-table">
		<table class="tablesaw tablesaw-stack" data-tablesaw-mode="stack" role="presentation">
			<thead>
				<tr>
					<th width="1%">Option</th>
					<!-- ko fastForEach: tableColumns -->
					<th data-bind="
							html: utils.htmlDecode(ko.unwrap($data).label),
							css: ko.unwrap($data).headerClass,
							attr: {
								width: ko.unwrap($data).width
							}
						">
					</th>
					<!-- /ko -->
				</tr>
			</thead>
			<!-- ko template: { afterRender: function() { $(document).trigger('enhance.tablesaw'); } } -->
				<tbody data-bind="fastForEach: rowCollection">
					<tr>
						<td>
							<select style="width: auto;" data-bind="options: children, optionsText: 'name', optionsCaption: '-- Select Option --', value: selectedChild, optionsAfterRender: setOptionHtmlFromName">
								<!-- option data-bind="text: name, value: $data"></option -->
								<option data-bind="value: undefined">-- Select One--</option>
							</select>
						</td>
						<!-- ko fastForEach: $parent.tableColumns -->
							<!-- ko if: $parent.selectedChild() && $data.template -->
								<td data-bind="
										template: {name: template, data: $parent.selectedChild(), if: $parent.selectedChild },
										css: ko.unwrap($data).cellClass
									">
								</td>
							<!-- /ko -->

							<!-- ko if: $parent.selectedChild() && !$data.template -->
								<td data-bind="
										text: ($data.format || _.identity)($parent.selectedChild()[field]),
										css: ko.unwrap($data).cellClass
									">
								</td>
							<!-- /ko -->

							<!-- ko if: !$parent.selectedChild() -->
								<td><span data-bind="text: $data.placeholder ? $data.placeholder || '-' : '-'"></span></td>
							<!-- /ko -->
						<!-- /ko -->
					</tr>
				</tbody>
			<!-- /ko -->
		</table>
	</div>
</script>

<script type="text/html" id="catalog.input_qty_table">
	<div class="tablesaw-overflow qty-input-table">
		<table class="tablesaw tablesaw-stack" data-tablesaw-mode="stack" role="presentation">
			<thead>
				<tr data-bind="fastForEach: tableColumns">
					<th data-bind="
							html: utils.htmlDecode(ko.unwrap($data).label),
							css: ko.unwrap($data).headerClass,
							attr: {
								width: ko.unwrap($data).width
							}
						">
					</th>
				</tr>
			</thead>
			<!-- ko template: { afterRender: function() { $(document).trigger('enhance.tablesaw'); } } -->
				<tbody data-bind="fastForEach: children">
					<tr data-bind="fastForEach: $parent.tableColumns">
					<!-- ko if: $data.template -->
						<td data-bind="
								text: ko.unwrap($data).label != 'Image' ? ko.unwrap($data).label : '',
								css: ko.unwrap($data).label != 'Image' ? 'tablesaw__label-mobile' : '',
								visible: ko.unwrap($data).label != 'Image'
							">
						</td>
						<td data-bind="
								template: {name: template, data: ko.unwrap($parent) },
								css: ko.unwrap($data).cellClass
							">
						</td>
					<!-- /ko -->

					<!-- ko if: !$data.template -->
						<td data-bind="
								text: ko.unwrap($data).label != 'Image' ? ko.unwrap($data).label : '',
								css: ko.unwrap($data).label != 'Image' ? 'tablesaw__label-mobile' : '',
								visible: ko.unwrap($data).label != 'Image'
							">
						</td>
						<td data-bind="
								text: ($data.format || _.identity)(ko.unwrap($parent)[field]),
								css: ko.unwrap($data).cellClass
							">
						</td>
					<!-- /ko -->
					</tr>
				</tbody>
			<!-- /ko -->
		</table>
	</div>
</script>

<script type="text/html" id="catalog.product_title">
	<div class="page-header detail-title">
		<h1 data-bind="html: selectedProduct().name() || name()"></h1>
		<!-- ko template: 'catalog.product_links' --><!-- /ko -->
	</div>
</script>

<script type="text/html" id="catalog.product_view">
	<!-- ko template: { name: "catalog.product_title", data: selectedProduct } --><!-- /ko -->
	<div id="product_view" class="row-fluid product_view">
		<div data-bind="attr: { class: oConfig.detailConfig.gridLeftColumnClass + ' product-detail__left' }">
			<!-- ko if: !oConfig.detailConfig.showMainImage -->
				<!-- ko template: 'catalog.detail_info_container' --><!-- /ko -->
			<!-- /ko -->
			<!-- ko if: oConfig.detailConfig.showMainImage -->
				<div id="product_images" data-bind="template: { name: 'catalog.image_gallery', data: selectedProduct }"></div>
			<!-- /ko -->
		</div>
		<div data-bind="attr: { class: oConfig.detailConfig.gridRightColumnClass  + ' product-detail__right'}">
			<!-- ko if: !oConfig.detailConfig.showMainImage -->
				<span data-bind="template: { name: 'catalog.smart_lists', data: selectedProduct() }"></span>
			<!-- /ko -->
			<!-- ko if: oConfig.detailConfig.showMainImage -->
				<!-- ko template: 'catalog.detail_info_container' --><!-- /ko -->
			<!-- /ko -->
		</div>
	</div>
	<!-- ko template: 'catalog.additional_info' --><!-- /ko -->
</script>

<script type="text/html" id="catalog.detail_info_container">
	<div class="detail-product-info">
		<div data-bind="template: 'catalog.share_code'"></div>
		<span class="product_view__detail-info" data-bind="template: 'catalog.detail_info'"></span>
		<div class="detail-docs" data-bind="template: { if: oConfig.detailConfig.showDocuments && !selectedProduct().usingDownloadsTab(),  name: 'catalog.documents', data: selectedProduct().documents() }"></div>
		<div data-bind="
			template: {
				name: 'promotions.descriptions',
				if: promoDescriptions && promoDescriptions.length,
				data: {
					title: 'Product on Promotion',
					descriptions: promoDescriptions,
					selectedProduct: selectedProduct
				}
			}
		">
		</div>
		<!-- ko if: oConfig.detailConfig.showDescription && oConfig.detailConfig.showProductDescriptionTop -->
			<span data-bind="template: { name: 'catalog.product_description', data: selectedProduct }"></span>
		<!-- /ko -->
		<div class="detail-child-selector">
			<span data-bind="template: { name: 'catalog.child_selectors', if: $data.childSelectors, data: $data.childSelectors }"></span>
		</div>
		<span data-bind="template: 'catalog.rating_detail'"></span>
		<span data-bind="template: { name: 'catalog.add_ons', data: selectedProduct }"></span>
		<div id="atcform">
			<div data-bind="template: { name: 'catalog.atc_full', data: selectedProduct }"></div>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.child_selectors">
	<!-- ko foreach: $data -->
		<span data-bind="template: 'catalog.child_droplist_select'"></span>
	<!-- /ko -->
</script>

<script type="text/html" id="catalog.child_droplist_select">
	<div class="child-droplist-selector" style="clear: left;"
		 data-bind="visible: showSelector">
		<label data-bind="html: utils.htmlDecode(label), attr: { for: field }">
		</label>
		<select data-bind="
			attr: { id: field, name: field },
			options: options,
			optionsText: 'option',
			value: selectedOption,
			optionsCaption: '-- Select One --',
			optionsAfterRender: function (option, item) { setChildOptionDisable(field, option, item) },
			enable: !!options.length
		">
		</select>
	</div>
	<div data-bind="if: $data.loading">
		<div class="sk-three-bounce" style="float: left;">
			<div class="sk-child sk-bounce1"></div>
			<div class="sk-child sk-bounce2"></div>
			<div class="sk-child sk-bounce3"></div>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.product_description">
	<div class="product-detail__description-wrap" data-bind="if: description() || $parent.description()">
		<h2 class="product-detail__description-title" data-bind="html : oConfig.labels.description"></h2>
		<span class="product-detail__description-text" data-bind="html: description() || $parent.description()"></span>
	</div>
</script>

<script type="text/html" id="catalog.additional_info">
	<span data-bind="if: selectedProduct().useTabs(), attr: { 'data-layout' : oConfig.detailConfig.tabLayoutMode }" >
		<!-- ko template: 'catalog.advanced_tabs' --><!-- /ko -->
	</span>
</script>

<script type="text/html" id="catalog.additional_sections">
	<span data-bind="ifnot: selectedProduct().useTabs(), attr: { 'data-layout' : oConfig.detailConfig.pageLayoutMode }" >
		<!-- ko if: oConfig.detailConfig.showDescription && !oConfig.detailConfig.showProductDescriptionTop -->
			<span data-bind="template: { name: 'catalog.product_description', data: selectedProduct }"></span>
		<!-- /ko -->
		<span data-bind="template: { name: 'catalog.related_products', data: related().filter(function(item) { return !item.relatedGroup() }) }"></span>
		<span data-bind="template: { name: 'catalog.second_related_products', data: secondRelated }"></span>
		<span data-bind="template: 'catalog.reviews'"></span>
		<!-- ko if: oConfig.detailConfig.showMainImage -->
			<span data-bind="template: { name: 'catalog.smart_lists', data: selectedProduct() }"></span>
		<!-- /ko -->
	</span>

	<span data-bind="template: { name: 'catalog.also_bought', data: alsoBought }"></span>
	<span data-bind="template: { name: 'catalog.recently_viewed', data: $parent.recentlyViewed }"></span>
</script>



<script type="text/html" id="catalog.advanced_tabs">
	<div id="tabs" class="detail_desc">
		<div class="tabbable tabbable-detail" >
			<span data-bind="template: 'catalog.tab_header'"></span>
			<span data-bind="template: 'catalog.tab_content'"></span>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.tab_header">
	<ul id="nav-tabs" class="nav nav-tabs" data-bind="foreach: selectedProduct().tabs">
		<li data-bind="attr: { 'data-tabtype': dynamicSource, id: 'tab' + ($index()+1) }">
			<a data-toggle="tab" data-bind="attr: { href: '#tab_section_' + ($index() + 1) }">
				<span data-bind="html: label || _.startCase(dynamicSource)"></span>
			</a>
		</li>
	</ul>
</script>

<script type="text/html" id="catalog.tab_content">
	<div class="tab-content" data-bind="foreach: { data: selectedProduct().tabs, afterUpdate: selectFirstTab }">
		<div class="tab-pane" data-bind="attr: { id: 'tab_section_' + ($index() + 1) }">
			<p data-bind="html: staticPos === 'above' ? staticContent : ''"></p>
			<span data-bind="
				template: {
					name: 'catalog.tab_' + dynamicSource,
					data: {
						tab: $data,
						mainProduct: $parent
					}
			}">
			</span>
			<p data-bind="html: staticPos === 'below' ? staticContent : ''"></p>
		</div>
	</div>
</script>

<script type="text/html" id="catalog.tab_description">
	<span data-bind="html: mainProduct.selectedProduct().description"></span>
</script>

<script type="text/html" id="catalog.tab_downloads">
	<ul class="doc_downloads" data-bind="with: mainProduct.selectedProduct().documents">
		<!-- ko foreach: $data -->
			<li data-bind="if: link() && name()">
				<a data-bind="attr: { href: utils.buildImagePath(link()) }, text: name" target="_blank" ></a>
			</li>
		<!-- /ko -->
	</ul>
</script>

<script type="text/html" id="catalog.tab_web_page">
	<span data-bind="template: 'catalog.web_page_get'"></span>
</script>

<script type="text/html" id="catalog.web_page_get">
	<span data-bind="
		load: {
			url: mainProduct.selectedProduct().getWebPage(tab.webPageId),
			cache: true
		}
	">
	</span>
</script>

<script type="text/html" id="catalog.tab_related_products">
	<span data-bind="template: { name: 'catalog.related_products', data: mainProduct.related().filter(function(item) { return item.relatedGroup() == tab.relatedProductsGroup }) }"></span>
</script>

<script type="text/html" id="catalog.tab_second_related_products">
	<span data-bind="template: { name: 'catalog.second_related_products', data: mainProduct.secondRelated }"></span>
</script>

<script type="text/html" id="catalog.tab_reviews">
	<!-- ko template: { name: 'catalog.reviews', data: mainProduct } --><!-- /ko -->
</script>

<script type="text/html" id="catalog.tab_smart_list">
	<span data-bind="template: { name: 'catalog.smart_lists', data: mainProduct.selectedProduct() }"></span>
</script>

<script type="text/html" id="catalog.tab_rys">
	<!-- ko template: { name: 'catalog.product_facets_table', data: mainProduct.selectedProduct() } --><!-- /ko -->
</script>

<script type="text/html" id="catalog.product_facets_table">
	<!-- ko if: facets -->
		<table class="table table-striped">
			<tbody>
				<tr data-bind="foreach: facets">
					<th data-bind="text: search_group"></th>
					<td data-bind="text: search_term"></td>
				</tr>
			</tbody>
		</table>
	<!-- /ko -->
</script>

<script type="text/html" id="catalog.tab_hook">
	<span data-bind="template: { name: 'tab_hook_' + tab.hook, data: viewModel }"></span>
</script>


<script type="text/html" id="catalog.tab_none">

</script>


	<script type="text/html" id="catalog.reviews">
		<!-- ko if: oConfig.useReviews -->
			<h2 data-bind="html : oConfig.labels.reviews"></h2>
			<div
				id="reviews"
				itemprop="aggregateRating"
				itemscope
				itemtype="http://schema.org/AggregateRating"
			>
				<!-- ko if: reviews.size() -->
					<div class="well reviews-header">
						<h4 data-bind=" html : oConfig.labels.averageRating"></h4>
						<p>
							<div class="raty" data-bind="raty: averageRating"></div>
							<small class="muted">
								<span itemprop="ratingValue" data-bind="text: averageRating().toFixed(1)"></span>
								out of
								<span itemprop="bestRating">5.0</span> stars
							</small>
						</p>
						<div class="btn-group">
							<!-- ko if: !oConfig.allowAddReviews -->
								<a class="btn btn-small" data-bind="attr: { href: utils.loginUrl }, html: oConfig.labels.reviewSignInText"></a>
							<!-- /ko -->
							<!-- ko if: oConfig.allowAddReviews -->
								<a
									class="global-modal btn btn-primary"
									data-size="large"
									data-backdrop="static"
									data-bind="
										attr: { href: 'ae_sf_review_comment.asp?contentkey=' + key() },
										html: oConfig.labels.reviewsAddText "
								></a>
							<!-- /ko -->
						</div>
					</div>
				<!-- /ko -->
				<!-- ko template: { name: 'catalog.reviews_list', data: reviews } --><!-- /ko -->
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.reviews_list">
		<div class="media-list reviews-list">
			<!-- ko template: { name: 'catalog.review', if: size, foreach: items } --><!-- /ko -->
		</div>
		<!-- ko ifnot: size -->
			<p class="alert alert-info">This product has not been reviewed.</p>
			<!-- ko ifnot: oConfig.allowAddReviews -->
				<a class="btn" data-bind="attr: { href: utils.loginUrl }, html: oConfig.labels.reviewSignInText"></a>
			<!-- /ko -->
			<!-- ko if: oConfig.allowAddReviews -->
				<a
					class="global-modal btn btn-primary"
					data-bind="
						attr: { href: 'ae_sf_review_comment.asp?contentkey=' + $parent.key() },
						html: oConfig.labels.reviewsAddText "
					data-size="large"
				></a>
			<!-- /ko -->
		<!-- /ko -->
		<div class="btn-group reviews-paging" data-bind="if: numPages() > 1">
			<button class="btn" data-bind="click: page.decrement, enable: page() > 1">
				Prev
			</button>
			<button class="btn" data-bind="click: page.increment, enable: page() < numPages()">
				Next
			</button>
		</div>
	</script>

	<script type="text/html" id="catalog.review">
		<div class="media">
			<div class="media-body">
				<div class="media-heading">
					<div data-bind="raty: rating"></div>
					<small class="muted">By <span data-bind="text: name || 'Anonymous User'"></span> on <span data-bind="text: new Date(create_date).toDateString()"></span></small>
				</div>
				<div class="text-small" data-bind="text: comments"></div>
			</div>
			<!-- ko template: { name: 'catalog.review', if: children, foreach: children } --><!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.rating_detail">
		<div data-bind="if: oConfig.useReviews" class="average-rating-header">
			<div class="detail_rating detail_info">
				<!-- ko template: 'catalog.rating_score' --><!-- /ko -->
				<span data-bind="template: { name: 'catalog.read_reviews', if: ratingsCount }"></span>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.rating_score">
		<!-- ko if: oConfig.useReviews -->
			<div class="raty" data-bind="raty: averageRating"></div>
			<span class="muted text-xsmall" data-bind="text: ratingsCount() ? '(' + ratingsCount() + ' ' + utils.plural('review', ratingsCount()) + ')' : ''"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.read_reviews">
		<a
			href="#"
			class="btn btn-small btn-link"
			data-bind="
				text: oConfig.detailConfig.labels.readReviews,
				click: _.partial(utils.scrollTo, '#reviews')
			"
		></a>
	</script>

	<script type="text/html" id="catalog.product_actions">
		<!-- ko if: selectedProduct().showQuickAtc -->
			<!-- ko if: selectedProduct().isInCart -->
				<div class="already-in-cart muted text-small"><i class="fas fa-shopping-cart"></i> Already in Cart</div>
			<!-- /ko -->
			<div class="input-prepend input-append">
				<!-- ko if: hasQuantityRestrictions -->
					<a href="#0"
						class="add-on"
						data-bind="popover, attr: { 'data-content': quantityRestrictionsHtml, 'data-key' : key, 'id': 'pop-' + $.escapeSelector(sku().replace(/([^A-Za-z0-9[\]{}_.:-])\s?/g, '_')) }"
						data-trigger="hover"
						data-html="true"
						data-placement="top"
					>
						<i class="icon-question-sign"></i>
					</a>
				<!-- /ko -->
				<input
					data-bind="
						value: selectedProduct().selectedQty,
						init: function () {
							if (setSelectedQty()) {
								if(typeof qty != 'undefined' && qty() >= minQty()){
									selectedQty(qty());
								}else{
									selectedQty(minQty() || 1)
								}
							};
						},
						attr: {
							'min' : oConfig.useMinimumQuantity && minQty()  || 1,
							'step': oConfig.useQuantityIncrement && stepQty() || 1,
							'max' : oConfig.useMaximumQuantity && maxQty()
						},
						visible: !isChild() || oConfig.allowChildATC,
						validateQty
					"
					type="number"
					pattern="\d*"
					class="qty-input"
					placeholder="Qty"
					aria-label="Qty"
				>
				<!-- ko template: {name: 'catalog.product_actions_add', if: selectedProduct().childDisplayType() !== 'matrix-all'} --><!-- /ko -->
			</div>
			<div class="text-error" data-bind="visible: !questionsHaveValidAnswers() && currentParent().rowsAtcAttempted()">Please ensure all required fields are populated.</div>
		<!-- /ko -->

		<!-- ko if: !selectedProduct().showQuickAtc() && !allowQuickAddModal() -->
			<a class="btn btn-view-details" data-bind="
				attr: { href: link },
				visible: (isParent()) || ((!isChild() || oConfig.allowChildATC) && (showAtc) && !(oConfig.showChildrenSelection && selectedProduct().isChild())),
				html: oConfig.labels.selectOptionsLabel "></a>
		<!-- /ko -->
		<!-- ko if: !selectedProduct().showQuickAtc() && oConfig.allowQuickAdd && allowQuickAddModal() -->
			<a
				class="btn btn-view-details global-modal quick-add"
				data-bind="
					html: oConfig.labels.selectOptionsLabel,
					attr: { href: utils.buildQuickAddLink($data), id: 'quick-add_' + key() },
					visible: (isParent()) || ((!isChild() || oConfig.allowChildATC) && (showAtc) && !(oConfig.showChildrenSelection && selectedProduct().isChild())),
                    addModalHandler: { 'element' : $('.quick-add'), 'handler' : function(data){  fncReloadCartWindow();  viewModel.activeCart(data);} }
				"
			></a>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.product_actions_add">
		<div class="btn-group">
			<button type="button"
				class="prod-card__atc btn btn-cart-add"
				data-bind="
					html: atcButtonText(),
					click: addToCart,
					visible: function(){
						if(currentParent().childDisplayType() === 'input-qty' && !oConfig.showListViewATC){
							return false;
						}else{
							return (!isChild() || oConfig.allowChildATC) && (getActiveLayout() !== 'list' || oConfig.showListViewATC) && (!(currentParent().childDisplayType() === 'add-row') || !!oConfig.childSkuMatch)
						}
					}() ,
					enable: isQtyValid()
				">
			</button>
			<!-- ko if: oConfig.showFavLink && oConfig.useSavedCarts  -->
				<button class="btn dropdown-toggle" data-toggle="dropdown">
						<i class="icon-angle-down"></i>
				</button>
				<ul class="dropdown-menu pull-right prod-card__atwrap">
					<!-- ko if: oConfig.showFavLink && oConfig.searchConfig.pageType != 'favlist' && currentParent().childDisplayType() !== 'add-row' -->
						<li class="prod-card__atf" data-bind="template: 'catalog.fav_link'"></li>
					<!-- /ko -->
					<!-- ko if: oConfig.useSavedCarts  -->
						<li class="prod-card__ats">
							<a href="#0" data-bind="click: addToSavedCart">
								<span data-bind="html: oConfig.labels.savedCartsLabels.addToSavedCart"></span>
							</a>
						</li>
					<!-- /ko -->
				</ul>
			<!-- /ko -->
			<!-- ko if: (oConfig.showFavLink && !oConfig.useSavedCarts) && oConfig.searchConfig.pageType != 'favlist' && currentParent().childDisplayType() !== 'add-row' -->
				<a class="btn global-modal" data-bind="attr: {
						title: utils.decodeHTML(oConfig.labels.favLink),
						'data-title': utils.decodeHTML(oConfig.labels.favLink),
						href: 'add_product_to_favorites.asp?p_id=' + key(),
						'aria-label': utils.decodeHTML(oConfig.labels.favLink)
					}, tooltip"
					data-icon="heart"
					data-size="small">
					<i class="icon-heart"></i>
				</a>
			<!-- /ko -->
			<!-- ko if: !oConfig.showFavLink && oConfig.useSavedCarts -->
				<button type="button" class="btn" data-bind="attr: {
						title: utils.decodeHTML(oConfig.labels.savedCartsLabels.addToSavedCart)
					}, click: addToSavedCart, tooltip">
					<i data-bind="attr: {
							class: oConfig.labels.savedCarts.toLowerCase() == 'quote' ? 'icon-comments' : 'icon-save'
						}"></i>
				</button>
			<!-- /ko -->
		</div>
		<!-- ko if: (currentParent().childDisplayType() == 'add-row') -->
			<button type="button" class="btn btn-danger add-row__remove-btn" data-bind="attr: {
					title: utils.decodeHTML(oConfig.labels.addRowRemoveRowLink) || 'Remove',
					'data-title': oConfig.labels.addRowRemoveRowLink || 'Remove'
					}, click: function() { currentParent().removeRow($data.rowKey) }">
				<i class="icon-trash"></i>
			</button>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.atc_full">
		<!-- ko ifnot: $data.type === 'parent' -->
			<!-- ko if: oConfig.useIdp -->
				<!-- ko template: 'catalog.inventory' --><!-- /ko -->
			<!-- /ko -->
			<fieldset id="cart_options" data-bind="visible: oConfig.useCartOptions && selectedProduct().hasCartOptions() ">
			<legend>Additional Options</legend>
				<!-- ko template: { name: 'catalog.cart_options', data: selectedProduct, if: selectedProduct().questions().length > 0 } --><!-- /ko -->
			</fieldset>
			<!-- ko template: 'catalog.configurator' --><!-- /ko -->
			<!-- ko if: oConfig.UseTaxExempt -->
				<!-- ko template: 'catalog.tax_exempt' --><!-- /ko -->
			<!-- /ko -->
		<!-- /ko -->
		<!-- ko if: $data.isDangerous -->
			<!-- ko template: 'catalog.hazmat' --><!-- /ko -->
		<!-- /ko -->
		<!-- ko if: oConfig.detailConfig.showSoftGoodAuthorizations -->
			<!-- template: 'catalog.softgoods' -->
		<!-- /ko -->
		<div class="prod-pricing" data-bind="template: { name: priceDisplay, data: selectedProduct } "></div>
		<!-- ko if: utils.isMainProduct($data) ? showAtc : selectedProduct().showAtc -->
			<!-- ko template: { name: 'catalog.atc_form_submit', data: selectedProduct } --><!-- /ko -->
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.product_quantity">
		<div>
			<div class="input-prepend product-detail__qty-wrap">
				<label class="add-on product-detail__qty-label" data-bind="for: 'next'">QTY:</label>
				<input
					data-bind="
						value: selectedQty,
						init: function () { if (setSelectedQty()) selectedQty(minQty() || 1); },
						attr: {
							'min' : oConfig.useMinimumQuantity && (minQty() || stepQty()) || 1,
							'step': oConfig.useQuantityIncrement && stepQty() || 1,
							'max' : oConfig.useMaximumQuantity && maxQty(),
							'id'  : 'qty_'+key()+'_0'
						},
						validateQty
					"
					onclick="this.focus();this.select();"
					type="number"
					pattern="\d*"
					class="qty-input product-detail__qty-input"
				>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.atc_form_submit">
		<div class="atc-large">
			<!-- ko if: atcErrorText() != "" -->
				<div class="alert alert-error" data-bind="html:atcErrorText"></div>
			<!-- /ko -->
			<div class="pull-left" data-bind="template: 'catalog.product_quantity'"></div>
			<div class="media-body">
				<div class="btn-group">
					<button
						type="button"
						class="btn btn-primary product-detail-atc__button"
						data-bind="
							click: addToCart,
							html: atcButtonText()"
					></button>
				</div>
				<div data-bind="template: { name: 'catalog.saved_cart_form_submit', if: oConfig.useSavedCarts }"></div>
			</div>
		</div>
		<div data-bind="template: { name: 'catalog.qty_restrictions', if: hasQuantityRestrictions }"></div>
	</script>

	<script type="text/html" id="catalog.atc_qty_input">
		<div class="prod-actions" data-bind="template: 'catalog.product_actions'"></div>
	</script>


	<script type="text/html" id="catalog.atc_popup">
		<div id="atc_msg_product">
			<div style="margin: 5px auto;text-align: center;">
				<span data-bind="text: details.length"></span> <span data-bind="plural: details">product</span> added to cart.
				<span data-bind="if: details.length === 1">
					<h3 data-bind="text: details[0].name"></h3>
					<img
						data-bind="
							if: details[0].pic(),
							attr: {
								src: utils.buildImagePath(details[0].pic() || oConfig.defaultImage),
								alt: details[0].thumbAltText() || details[0].name()
							}
						"
						onerror="utils.handleImageError(this)"
					/>
				</span>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.atc_popup_buttons">
		<div style="margin: 5px auto;text-align: center;">
			<a id="atc_msg_btn_close" class="btn btn-default" href="#" data-dismiss="modal" data-bind="text: oConfig.labels.continueShoppingLink"></a>
			<a id="atc_msg_btn_cart" class="btn btn-primary"  href="showcart.asp" data-bind="text: oConfig.labels.showCartLink"></a>
		</div>
	</script>

	<script type="text/html" id="catalog.atc_splash">
		<div class="sk-wave">
			<div class="sk-rect sk-rect1"></div>
			<div class="sk-rect sk-rect2"></div>
			<div class="sk-rect sk-rect3"></div>
			<div class="sk-rect sk-rect4"></div>
			<div class="sk-rect sk-rect5"></div>
		</div>
	</script>

	<script type="text/html" id="catalog.atc_body">
		<!-- ko template: 'catalog.atc_popup' --><!-- /ko -->
		<!-- ko ifnot: cart -->
			<!-- promoMessages: details -->
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.promo_bar">
		<div data-bind="promoMessages: details"></div>
	</script>

	<script type="text/html" id="catalog.atc_invalid_qty">
		<div class="catalog__atc-invalid-qty" data-bind="text: oConfig.labels.invalidQtyText"></div>
	</script>

	<script type="text/html" id="catalog.saved_cart_select_popup">
		<div class="saved-cart-popup__container">
			<!-- ko if: oConfig.isLoggedIn -->
				<h5><span data-bind="text: oConfig.labels.savedCartsLabels.modalCreateNew"></span></h5>
				<div class="input-append">
					<input type="text" id="nickname" data-bind="attr: { placeholder: oConfig.labels.savedCartsLabels.modalCreateNewInputPlaceholder }">
					<button
						id="saved_cart_add"
						class="btn btn-primary input-append"
						data-bind="
							init: function () {
								$data.errorMessage = ko.observable();
							},
							click: function () {
								var input = $('#nickname');
								var nickname = input.val().trim();

								if (!nickname) {
									input.val('');
									errorMessage('Please enter a nickname');
								} else if (_.includes(_.pluck(ko.toJS(savedCarts), 'nickname'), nickname)) {
									errorMessage('That nickname is already in use');
								} else {
									selectedCart({ key: utils.createGuid(), nickname: nickname });
								}
							},
							text: oConfig.labels.savedCartsLabels.modalCreateNewSaveButton"
					>
						<i class="icon-save"></i>
						</button>
				</div>
				<!-- ko if: errorMessage -->
					<div class="alert alert-error" data-bind="text: errorMessage"></div>
				<!-- /ko -->
				<h5 data-bind="html: oConfig.labels.savedCartsLabels.modalExisting"></h5>
				<!-- ko template: 'catalog.saved_carts_table'--><!-- /ko -->
			<!-- /ko -->
			<!-- ko ifnot: oConfig.isLoggedIn -->
				<div class="text-center">
					<p class="alert alert-info without-close">You must be signed in to take this action.</p>
					<a data-bind="attr: { href: utils.loginUrl }" class="btn btn-primary btn-block">Sign In Now</a>
					<button type="button" class="btn btn-block" data-dismiss="modal">Cancel</button>
				</div>
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.saved_carts_table">
		<!-- ko if: savedCarts.length > 0 -->
			<div class="list-group" data-bind="foreach: { data: savedCarts, as: 'cart' }">
				<a href="#"
					 data-bind="
					 	click: function () {
					 		$parent.selectedCart(cart);
					 	},
						spacedtext: cart.nickname || cart.refId,
						attr: { title: cart.nickname || cart.refId }
					 " class="list-group-item">
				</a>
			</div>
		<!-- /ko -->
		<!-- ko ifnot: savedCarts.length > 0 -->
			<div class="list-group">
				<div class="list-group-item">None found</div>
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.saved_cart_form_submit">
		<span data-bind="if: showQuickAtc">
			<button class="btn btn-small btn-secondary" data-bind="click: addToSavedCart, html: oConfig.labels.savedCartsLabels.addToSavedCart"></button>
		</span>
	</script>

	<script type="text/html" id="catalog.saved_cart_confirmation_body">
		<div class="saved-cart-popup__container">
			<div class="text-center" style="display: block;">
				<h4 class="text-success">
					<span data-bind="plural: details, text: oConfig.labels.savedCartsLabels.itemText"></span>
					<span data-bind="text: oConfig.labels.savedCartsLabels.modalConfirmationSubHeader"></span>
				</h4>
				<p><strong class="cart-sc-nm" data-bind="text: cart.nickname"></strong></p>
				<div class="well well-small">
					<a
						class="btn btn-block"
						data-bind="attr: {
							href : oConfig.sessionData.orderfrontUrl + '/payment.asp?o_key=' + cart.key
						}"
					>
						<span data-bind="text: oConfig.labels.savedCartsLabels.modalConfirmationViewButton"></span>
					</a>
					<a href="pending_orders.asp" class="btn btn-block"><span data-bind="text: oConfig.labels.savedCartsLabels.modalConfirmationManageButton"></span></a>
					<a href="#" class="btn btn-block" data-dismiss="modal"><span data-bind="text: oConfig.labels.savedCartsLabels.modalConfirmationCloseButton"></span></a>
				</div>
			</div>
		</div>
	</script>


	<script type="text/html" id="catalog.qty_restrictions">
		<div class="text-small muted" data-bind="attr: { 'data-key' : key() } ">
			<div id="qty_controls_msg" >
				<span data-bind="if: oConfig.useMinimumQuantity && selectedUom().minQty() > 0">
					<span data-bind="text: oConfig.labels.minQty"></span>: <span data-bind="text: selectedUom().minQty()"></span><br>
					<input type="hidden" data-bind="attr: { name: 'minQty_'+ key() }, value: selectedUom().minQty()" />
				</span>

				<span data-bind="if: oConfig.useMaximumQuantity && selectedUom().maxQty() > 0">
					<span data-bind="text: oConfig.labels.maxQty"></span>: <span data-bind="text: selectedUom().maxQty()"></span><br>
					<input type="hidden" data-bind="attr: { name: 'maxQty_'+ key() }, value: selectedUom().maxQty()" />
				</span>

				<span data-bind="if: oConfig.useQuantityIncrement && selectedUom().step() && selectedUom().step() !== 1">
					<span data-bind="text: oConfig.labels.step"></span>: <span data-bind="text: selectedUom().step()"></span><br>
					<input type="hidden" data-bind="attr: { name: 'qty_increment_'+ key() }, value: selectedUom().step()" />
				</span>
			</div>
		</div>
	</script>

	<script type="text/html" id="catalog.inventory">
		<span data-bind="if: inventory.isInventoryItem() && oConfig.useIdp">
			<span data-bind="template: warehouseTemplate"></span>
		</span>
	</script>

	<script type="text/html" id="catalog.selected_product_price_display">
		<span data-bind="if: unitPrice() === 0 && oConfig.showZeroPriceMessage && showPrice">
			<ul class="unstyled prod-pricing__wrap">
				<li class="retail">
					<span data-bind="text: oConfig.zeroPriceMessage"></span>
				</li>
				<li class="text-small" data-bind="template: { name: priceBreaksTemplate, if: oConfig.useBreaks }"></li>
			</ul>
		</span>
		<span data-bind="if: !(unitPrice() === 0 && oConfig.showZeroPriceMessage) && showPrice && uomPrice()">
			<ul class="price-display__wrap unstyled">
				<!-- ko if: priceTrace -->
				<li class="text-small">
					<div class="alert alert-info" data-bind="html: priceTrace().replace(/\n/gi,'<br>') "></div>
				</li>
				<!-- /ko -->
				<li class="retail">
					<b data-bind="html: utils.formatPrice(unitPrice())"></b>
					<span class="prod-uom" data-bind="template: 'catalog.uom'"></span>
				</li>
				<!-- ko if: showYouSave -->
					<li class="sretail">
						<del data-bind="html: utils.formatPrice(suggestedPrice())"></del>
						<span class="yousave" data-bind="spacedtext: oConfig.labels.youSaveLabel + ' ' + youSavePercent()"></span>
					</li>
				<!-- /ko -->
				<li class="text-small" data-bind="template: { name: priceBreaksTemplate, if: oConfig.useBreaks }"></li>
			</ul>
		</span>
		<!-- ko if: (!showPrice || !showAtc) && oConfig.showPricingOrderEntry -->
			<div class="retail" data-bind="html: $data.mapPriceMessage"></div>
		<!-- /ko -->

		<!-- ko if: !oConfig.showPricingOrderEntry -->
			<div class="hidden-price" data-bind="html: utils.drawHidePriceMessage()"></div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.configurator_price_display">
		<div class="retail">
			<b data-bind="html: utils.formatPrice(unitPrice())"></b>
			<span class="prod-uom" data-bind="template: 'catalog.uom'"></span>
		</div>
	</script>

	<script type="text/html" id="catalog.input_qty_sku_display">
		<!-- ko if : oConfig.detailConfig.inputQtyLinkToChild -->
			<a data-bind="html: sku, attr: { 'href' : link}"></a>
		<!-- /ko -->
		<!-- ko if : !oConfig.detailConfig.inputQtyLinkToChild -->
			<span data-bind="html: sku"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.input_qty_nm_display">
		<!-- ko if : oConfig.detailConfig.inputQtyLinkToChild -->
			<a data-bind="html: name, attr: { 'href' : link}"></a>
		<!-- /ko -->
		<!-- ko if : !oConfig.detailConfig.inputQtyLinkToChild -->
			<span data-bind="html: name"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.input_qty_thumb_display">
		<!-- ko if : oConfig.detailConfig.inputQtyLinkToChild -->
			<a data-bind="attr: { 'href' : link}">
				<img data-bind=" attr: { src: utils.buildImagePath(thumb()), alt: name }" onerror="utils.handleImageError(this)">
			</a>
		<!-- /ko -->
		<!-- ko if : !oConfig.detailConfig.inputQtyLinkToChild -->
			<img data-bind=" attr: { src: utils.buildImagePath(thumb()), alt: name }" onerror="utils.handleImageError(this)">
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.input_qty_promo_display">
		<!-- ko if : promoDescriptions.length -->
			<div class="promo-icon" data-bind="attr: { title: utils.decodeHTML(setPromoDescriptionTitleText(promoDescriptions)) }">P</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.price_start_at">
		<!-- ko if: !oConfig.showPricingOrderEntry -->
			<div class="hidden-price" data-bind="html: utils.drawHidePriceMessage()"></div>
		<!-- /ko -->
		<!-- ko if: oConfig.showPricingOrderEntry && childStartingPrice -->
			<span class="starting-price" data-bind="html: oConfig.searchConfig.labels.pricesStartingAt + utils.formatPrice(childStartingPrice())"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.qty_breaks">
		<span data-bind="if: showPrice && selectedUom().hasBreaks() && processedBreaks().length > 1">
			<a href="#" data-bind="text: oConfig.labels.breaks, click: function() { showBreaks(!showBreaks()); }"></a><br>
		</span>
		<span data-bind="visible: showBreaks">
			<!-- ko template: 'catalog.qty_breaks_table' --><!-- /ko -->
		</span>
		<!-- ko if: !oConfig.showPricingOrderEntry -->
			<div class="hidden-price" data-bind="utils.drawHidePriceMessage()"></div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.qty_breaks_table">
		<span data-bind="if: showBreaks && showPrice && processedBreaks().length > 1">
			<table id="breaks_table" class="table table-bordered" border="0" cellpadding="0" cellspacing="0">
				<caption data-bind="html: oConfig.priceBreaksTableHeader"></caption>
				<tr>
					<td>Quantity Range</td>
					<td>Price Each</td>
				</tr>
				<tbody data-bind="fastForEach: processedBreaks">
					<!-- ko if: range -->
					<tr>
						<td data-bind="text: range"></td>
						<td data-bind="text: utils.formatPrice(price)"></td>
					</tr>
					<!-- /ko -->
				</tbody>
			</table>
		</span>

		<!-- ko if: !oConfig.showPricingOrderEntry -->
			<div class="hidden-price" data-bind="html: utils.drawHidePriceMessage()"></div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.breaks_off">

	</script>



	<script type="text/html" id="catalog.related_products">
		<div id="related_products" class="clearfix detail_related" data-bind="if: oConfig.detailConfig.useRelatedProducts">
			<span data-bind="if: $data.length > 0">
				<h2 data-bind="html: oConfig.detailConfig.labels.relatedProducts"></h2>
				<span data-bind="template: 'catalog.simple_product_gallery'"></span>
			</span>
		</div>
	</script>

	<script type="text/html" id="catalog.second_related_products">
		<div id="second_related_products" class="clearfix detail_related" data-bind="if: oConfig.detailConfig.useSecondRelatedProducts">
			<span data-bind="if: $data.length > 0">
				<h2 data-bind="html: oConfig.detailConfig.labels.secondRelatedProducts"></h2>
				<span data-bind="template: 'catalog.simple_product_gallery'"></span>
			</span>
		</div>
	</script>

	<script type="text/html" id="catalog.also_bought">
		<div id="also_bought" class="clearfix detail_related" data-bind="if: oConfig.detailConfig.useAlsoBoughtProducts">
			<span data-bind="if: $data.length > 0">
				<h2 data-bind="html: oConfig.detailConfig.labels.alsoBoughtProducts"></h2>
				<span data-bind="template: 'catalog.simple_product_gallery'"></span>
			</span>
		</div>
	</script>

	<script type="text/html" id="catalog.add_ons">
		<div id="add_ons" class="clearfix detail_related" data-bind="if: oConfig.detailConfig.useAddOnProducts">
			<!-- ko if: selectedProduct().showAddOns && selectedProduct().addOns().length > 0 && Array('droplist', 'checkboxes', 'radio').includes(selectedProduct().addOnDisplay) -->
				<div class="add-on-container well">
					<p data-bind="html: selectedProduct().addOnLabel"></p>
					<span data-bind="template: 'catalog.add_on_' + selectedProduct().addOnDisplay "></span>
				</div>
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.add_on_droplist">
			<select style="width: auto;" data-bind="
				options: selectedProduct().addOnOptions,
				optionsText: function(item){ 
					return '(' + utils.formatPrice(item().selectedUom().price()) + ') ' + item().name(); 
				},
				value: selectedProduct().selectedAddOn,
				optionsCaption: '-- Select One --',
				"
			>
			</select>
			<!-- ko if: selectedProduct().selectedAddOn -->
				<label class="product-add-on-label product-detail__qty-label" data-bind="for: 'next'" for="for_binding_1">QTY:</label>
				<input 
					type="number"
					pattern="\d*"
					data-bind="
						value: selectedProduct().selectedAddOn().selectedQty || 1,
						attr: {
							'min' : oConfig.useMinimumQuantity && (selectedProduct().selectedAddOn().minQty() || selectedProduct().selectedAddOn().stepQty()) || 1,
							'step': oConfig.useQuantityIncrement && selectedProduct().selectedAddOn().stepQty() || 1,
							'max' : oConfig.useMaximumQuantity && selectedProduct().selectedAddOn().maxQty(),
							'id': 'qty_' + selectedProduct().selectedAddOn().key() +'_0'
						},
						validateQty
					" 
					class="qty-input product-detail__qty-input add-on-qty"
				>
				<p class="add-on-info" 
				   data-bind="
					html: 
						utils.formatPrice(selectedProduct().selectedAddOn().selectedUom().price()) + ' ' + 
						selectedProduct().selectedAddOn().inventory.stockMessage()
					" 
				></p>
			<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.add_on_radio">
		<div >
			<ul class="add-on-radio-list">
			<!-- ko foreach: selectedProduct().addOnOptions -->
				<li>
					<input 
						type="radio"
						name = "add-on-radio"
						data-bind="
							value: $data,
							checked: $parent.selectedProduct().selectedAddOn,
							attr: {
								'id': 'key_'+key()
							}"
					>
					<label class="add-on-prod-name" data-bind="html: name(), attr: { 'for':  'key_'+key() }"></label>
					<p class="add-on-info" data-bind="html: utils.formatPrice(selectedUom().price()) + ' ' + inventory.stockMessage()"></p>
				</li>
			<!-- /ko -->
			</ul>
			<!-- ko if: selectedProduct().selectedAddOn -->
				<label class="product-add-on-label product-detail__qty-label" data-bind="for: 'next'" for="for_binding_1">QTY:</label>
				<input 
					type="number"
					pattern="\d*"
					data-bind="
						value: selectedProduct().selectedAddOn().selectedQty || 1,
						attr: {
							'min' : oConfig.useMinimumQuantity && (selectedProduct().selectedAddOn().minQty() || selectedProduct().selectedAddOn().stepQty()) || 1,
							'step': oConfig.useQuantityIncrement && selectedProduct().selectedAddOn().stepQty() || 1,
							'max' : oConfig.useMaximumQuantity && selectedProduct().selectedAddOn().maxQty(),
							'id': 'qty_' + selectedProduct().selectedAddOn().key() +'_0'
						},
						validateQty
					" 
					class="qty-input product-detail__qty-input add-on-qty"
					style="width: 80px"
				>
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.add_on_checkboxes">
		<ul class="add-on-checkbox-list" >
			<!-- ko foreach: selectedProduct().addOnOptions -->
				<li style="padding-bottom: 10px;">
					<div class="pull-left" style="width: 66%; overflow: hidden;" >
						<input 
							type="checkbox"
							data-bind="
								value: $data,
								checked: $parent.selectedProduct().selectedAddOns,
								attr: {
									'id': 'key_'+key()
								}"
						>
						<label class="add-on-prod-name" data-bind="html: name(), attr: { 'for':  'key_'+key() }"></label>
						<p class="add-on-info" data-bind="html:utils.formatPrice(selectedUom().price()) + ' ' + inventory.stockMessage()" style="font-size: .85em; margin: -10px 0 0 35px;"></p>
					</div>
					<div class="pull-right">
						<label class="product-add-on-label product-detail__qty-label" data-bind="for: 'next'" for="for_binding_1">QTY:</label>
						<input 
							type="number"
							pattern="\d*"
							data-bind="
								init: function(){ console.log($data.minQty()); return $data.minQty() || 1; },
								value: $data.selectedQty,
								attr: {
									'min' : oConfig.useMinimumQuantity && ($data.minQty() || $data.stepQty()) || 1,
									'step': oConfig.useQuantityIncrement && $data.stepQty() || 1,
									'max' : oConfig.useMaximumQuantity && $data.maxQty(),
									'id': 'qty_' + $data.key() +'_0'
								},
								validateQty
							" 
							class="qty-input product-detail__qty-input add-on-qty"
							style="width: 80px; text-align: right;"
						>
					</div>
				</li>
			<!-- /ko -->
		</ul>
	</script>

	<script type="text/html" id="catalog.recently_viewed">
		<div id="recently_viewed_products"
				 class="clearfix detail_related recently-viewed"
				 data-bind="if: oConfig.detailConfig.useRecentlyViewedProducts && $data && $data.length > 0 && oConfig.searchConfig.pageType != 'favlist'">
			<span data-bind="if: oConfig.centerRecentlyViewed">
				<h2 class="recently-viewed__title -centered" data-bind="html: oConfig.detailConfig.labels.recentlyViewedProducts"></h2>
				<span class="recently-viewed__gallery -centered" data-bind="template: 'catalog.simple_product_gallery'"></span>
			</span>
			<span data-bind="if: !oConfig.centerRecentlyViewed">
				<h2 class="recently-viewed__title" data-bind="html: oConfig.detailConfig.labels.recentlyViewedProducts"></h2>
				<span class="recently-viewed__gallery" data-bind="template: 'catalog.simple_product_gallery'"></span>
			</span>
		</div>
	</script>

	<script type="text/html" id="catalog.simple_product_gallery">
			<div class="prod-listings" data-bind=" fastForEach: { data: $data }" data-layout="gallery">
				<!-- ko template: 'catalog.product_card' --><!-- /ko -->
			</div>
	</script>



	<script type="text/html" id="catalog.flags">
		<!-- ko foreach: flags -->
			<div data-bind="if: $data, attr: { 'id': 'flag' + ($index() + 1) }" class="product_flags">
				<!-- ko if: oConfig.flags[$index()].link && oConfig.flags[$index()].link != "\"\""-->
					<a data-bind="
						attr: {
							href: oConfig.flags[$index()].link,
							title: utils.decodeHTML(oConfig.flags[$index()].title)
						}"
						class="global-modal"
					>
						<img data-bind="attr: { src: utils.buildImagePath(oConfig.flags[$index()].pic) }" />
					</a>
				<!-- /ko -->
				<!-- ko ifnot: oConfig.flags[$index()].link && oConfig.flags[$index()].link  != "\"\""-->
					<img data-bind="attr: { src: utils.buildImagePath(oConfig.flags[$index()].pic) }" />
				<!-- /ko -->
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.flags_thumb">
		<!-- ko foreach: flags -->
			<div data-bind="if: $data, attr: { 'id': 'flag' + ($index() + 1) }" class="product_flags">
					<!-- ko if: oConfig.flags[$index()].link && oConfig.flags[$index()].link != "\"\""-->
					<a data-bind="
						attr: {
							href: oConfig.flags[$index()].link,
							title: utils.decodeHTML(oConfig.flags[$index()].title)
						}"
						class="global-modal"
					>
						<img data-bind="attr: { src: utils.buildImagePath(oConfig.flags[$index()].thumb) }" />
					</a>
				<!-- /ko -->
				<!-- ko ifnot: oConfig.flags[$index()].link && oConfig.flags[$index()].link  != "\"\""-->
					<img data-bind="attr: { src: utils.buildImagePath(oConfig.flags[$index()].thumb) }" />
				<!-- /ko -->
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.uom">
		<!-- ko if: selectedProduct().showQuickAtc -->
			<span data-bind="template: selectedProduct().uomTemplate"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.uom_select">
		<!-- ko if: oConfig.useUom -->
			/
			<select data-bind="
				options: selectedProduct().uomPrice,
				optionsText: 'description',
				value: selectedProduct().selectedUom
				"
			>
			</select>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.uom_input">
		<!-- ko if: oConfig.useUom && oConfig.useMultiUomMultiCurrency && uomPrice().length > 0 && uomPrice()[0].UomId -->
			<input type="hidden" data-bind="attr: { name: 'uom_id_'+ key() }, value: uomPrice()[0].UomId()">
			<small>/ <span data-bind="html: uomPrice()[0].UomName()"></span></small>
		<!-- /ko -->

		<!-- ko if: oConfig.useUom && !oConfig.useMultiUomMultiCurrency && uomPrice().length > 0  -->
			<input type="hidden" data-bind="attr: { name: 'uom_'+ key() }, value: uomPrice()[0].description">
			<small>/ <span data-bind="html: uomPrice()[0].description()"></span></small>
		<!-- /ko -->
	</script>

	<script type="text/html" id="warehouse_off">
				<!-- ko if: inventory.showQty() || !$.isNumeric(inventory.stock()) -->
			<div class="idp-instock__qty" data-bind="html: inventory.stock"></div>
		<!-- /ko -->

		<!-- ko if: inventory.showMessage -->
			<div class="idp-stock__message" data-bind="html: inventory.stockMessage"></div>
		<!-- /ko -->

		<!-- ko if: (inventory.inventoryStatus() === 'out' || inventory.inventoryStatus() === 'onorder') && oConfig.showInventoryWatch && show_inv_watch-->
			<span class="prod-inv-watch">
				<a
					data-bind="
						html: oConfig.searchConfig.labels.inventoryWatchLinkText,
						attr: {
							href: 'prod_inv_watch_add.asp?p_id=' + key() + '&p_nm=' + name() + '&p_sku=' + sku(),
							title: utils.decodeHTML(oConfig.labels.inventoryWatch),
							'data-title': oConfig.labels.inventoryWatch
						},
						tooltip: {
							placement: 'top',
							container: 'body'
						}"
					class="prod-inv-watch__btn global-modal btn btn-secondary"
					data-size="small"
				></a>
			</span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="warehouse_droplist">

		<label data-bind="
			attr : { 'for' : 'pw_id_' + key() },
			html: oConfig.labels.warehouses
		"></label>
		<select class="wh-droplist" data-bind="
			options: inventory.warehouses,
			optionsText: function(item){ return getInventoryDisplay( $data, item, true); },
			optionsValue: $data,
			value: selectedWarehouse,
			attr: {
				'id': 'pw_id_' + key(),
				'name': 'pw_id_' + key()
			}
		">
		</select>

	</script>

	<script type="text/html" id="warehouse_table">
		<table class="table table-bordered">
			<tr><th data-bind=" html : oConfig.labels.warehouses"></th>
			<th data-bind=" html : oConfig.labels.inventoryStatus"></th></tr>
			<tbody data-bind=" foreach: inventory.warehouses">
				<tr data-bind=" css : { default_warehouse : isDefault }">
					<td data-bind=" html: name"></td>
					<td data-bind=" html: getInventoryDisplay($parent, $data, false)"></td>
				</tr>
			</tbody>
		</table>
		<input type="hidden" data-bind="
			attr : {
				'id' : selectedWarehouse().key,
				'name' : selectedWarehouse().key,
				'value' : selectedWarehouse().key
			}
		">
	</script>

	<script type="text/html" id="warehouse_info">
		<div class="idp-warehouse clearfix" data-bind="if: selectedWarehouse().key">
			<div class="wh-selected">
				<div class="wh-selected-nm" data-bind="
					attr : { 'id' : 'selected_warehouse_' + selectedWarehouse.key },
					html : selectedWarehouse().name()
				"></div>
				<span data-bind="
					attr : { 'id' : 'stock_message_' + key() },
					html : getInventoryDisplay($parent, selectedWarehouse(), false)
				"></span>
			</div>
			<input type="hidden" data-bind="
				attr : {
					'id' : selectedWarehouse().key,
					'name' : selectedWarehouse().key,
					'value' : selectedWarehouse().key
				}
			">
		</div>
	</script>

<script>
function getInventoryDisplay(model, item, showWarehouseName){
	var quantity = item.qty_available();
	var message = '';

	if( model.inventory.inventoryStatus() == 'in' && model.inventory.inStockShowQty() ){
		if(quantity >= 0 || !$.isNumeric(quantity)){
			message = quantity;
		}else{
			message = '0';
		}
						
		if(model.inventory.useQtyLessThan() && quantity < model.inventory.qtyLessThanValue()){
			message = model.inventory.qtyLessThanDisplay();
		}

		if(model.inventory.useQtyGreaterThan() && quantity > model.inventory.qtyGreaterThanValue()){
			message = model.inventory.qtyGreaterThanDisplay();
		}
	}
	
	if( (model.inventory.inventoryStatus() == 'in' && model.inventory.inStockShowMessage()) || 
		(model.inventory.inventoryStatus() == 'out' && model.inventory.outStockShowMessage()) || 
		(model.inventory.inventoryStatus() == 'onorder' && model.inventory.onOrderShowMessage()) ){

		if(model.inventory.showMessage){
			message = message + ' ' + utils.removeHTML(model.inventory.stockMessage());
		}
	}

	if(showWarehouseName && message !== ''){
		message = '(' + message + ')';
	}

	if(showWarehouseName){
		message = item.name() + ' ' + message;
	}
	return message;
}
</script>


	<script type="text/html" id="catalog.image_gallery">
		<div class="detail-img-gallery">
			<div class="detail-img">
				<div class="detail-img-container">
					<div data-bind="template: 'catalog.flags'"></div>
					<!-- ko if: largePic() || $parent.largePic() -->
					<a
						id="detail_large"
						data-bind="
							attr: {
								href: utils.buildImagePath(largePic() || $parent.largePic()),
								title: utils.decodeHTML((picAltText() || $parent.picAltText() || name() || $parent.name()))
							},
							venobox
						"
						data-gall="detailmultipic"
						class="detail-img-main"
					>
						<!-- template: 'catalog.thumbnail_image' -->
					</a>
					<!-- /ko -->
					<!-- ko ifnot: largePic() || $parent.largePic() -->
						<!-- template: 'catalog.thumbnail_image' -->
					<!-- /ko -->
				</div>
				<div class="detail-img-enlarge" data-bind="if: largePic() || $parent.largePic()" >
					<a href="#" class="btn btn-small btn-link" onclick="$('#detail_large').click(); return false;">
						<i class="icon-zoom-in icon-fixed-width"></i>View Larger
					</a>
				</div>
			</div>
			<!-- ko if: multiPic().length > 0 || $parent.multiPic().length > 0 -->
				<div class="detail-img-multi" data-bind="foreach: { data: multiPic().length ? multiPic(): $parent.multiPic() }">
					<a class="detail-img-multi-item venobox vbox-item"
						 data-bind="attr: { href: utils.buildImagePath(link() || image()), title: utils.decodeHTML(alt()) }, venobox"
						 data-gall="detailmultipic">
						<img data-bind="attr: { src: utils.buildImagePath(image()) }">
					</a>
				</div>
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.thumbnail_image">
		<img
			data-bind="
				attr: {
					src: utils.buildImagePath(pic() || $parent.pic()),
					alt: thumbAltText() || $parent.thumbAltText() || name() || $parent.name()
				}
			"
			id="prodpicthumb"
			name="prodpic"
			itemprop="image"
			onerror="utils.handleImageError(this)"
		>
	</script>

	<script type="text/html" id="catalog.name_link">
		<a class="detail_link" data-bind="attr: { href: link, title: utils.decodeHTML(name()), 'data-key': key }, html: name"></a>
	</script>

	<script type="text/html" id="catalog.image_link">
		<a class="detail_link" data-bind="attr: { href: link, title: utils.decodeHTML(thumbAltText() || name()), 'data-key': key }">
			<img
				data-bind="
					attr: {
						src: utils.buildImagePath(thumb()),
						alt: thumbAltText() || name()
					}"
				onerror="utils.handleImageError(this)">
		</a>
	</script>


	<script type="text/html" id="catalog.details_link">
	</script>

	<script type="text/html" id="catalog.product_links">
		<div class="detail-links button-group">
			<!-- ko if: oConfig.showEmailFriend -->
				<!-- ko template: 'catalog.email_friend' --><!-- /ko -->
			<!-- /ko -->
			<!-- ko if: oConfig.showFavLink -->
				<!-- ko template: 'catalog.fav_button' --><!-- /ko -->
			<!-- /ko -->
			<!-- ko if: oConfig.showRFQLink -->
				<!-- ko template: 'catalog.rfq_button' --><!-- /ko -->
			<!-- /ko -->
		</div>
	</script>


	<script type="text/html" id="catalog.children_selection">
		<!-- ko foreach: $data.childSelectors -->
			<label data-bind="text: label, attr: { for: field }">
			</label>
			<select data-bind="
				attr: { id: field, name: field },
				options: options,
				optionsText: 'option',
				value: selectedOption,
				optionsCaption: '-- Select One --',
				optionsAfterRender: setOptionHTML
				"
			></select>
	<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.email_friend">
		<a class="btn btn-link global-modal"
			 data-bind="attr: { href: 'email_friend_request.asp?key=' + key() }"
			 data-icon="envelope"
			 data-size="small"
		>
			<i class="icon-envelope"></i>
			<span data-bind="html: oConfig.labels.emailFriend"></span>
		</a>
	</script>

	<script type="text/html" id="catalog.fav_link">
		<a class="global-modal"
			 data-bind="attr: { href: 'add_product_to_favorites.asp?p_id=' + key() }"
			 data-icon="heart"
			 data-size="small"
		>
			<span data-bind="html: oConfig.labels.favLink"></span>
		</a>
	</script>

	<script type="text/html" id="catalog.fav_button">
		<a class="btn btn-link global-modal"
			 data-bind="attr: { href: 'add_product_to_favorites.asp?p_id=' + key() }"
			 data-icon="heart"
			 data-size="small"
		>
			<i class="icon-heart"></i>
			<span data-bind="html: oConfig.labels.favLink"></span>
		</a>
	</script>

	<script type="text/html" id="catalog.remove_fav_button">
		<div class="remove-from-faves prod-fav-remove">
			<a
			   data-bind="
				   click: function() { fncRemoveItem(key(), selectedProduct()); },
				   attr: { title: utils.decodeHTML(oConfig.labels.removeFavLink),
				   href: 'javascript:void(0);'
				   }">
			   <i class="icon-remove"></i>
			   <span data-bind="html: oConfig.labels.removeFavLink"></span>
			</a>
		</div>
	</script>

	<script type="text/html" id="catalog.rfq_button">
		<a class="btn btn-link global-modal"
			 data-bind="attr: { href: 'rfq_ae.asp?lightbox=1&p_id=' + key() }"
			 data-icon="usd"
		>
			<i class="icon-usd"></i>
			<span data-bind="html: oConfig.labels.rfqLinkLabel"></span>
		</a>
	</script>

	<script type="text/html" id="catalog.share_code">

	</script>

	<script type="text/html" id="catalog.hazmat">
		<div class="hazmat">
			<span class="hazmat__label" data-bind="html: oConfig.labels.hazmat"></span>
			<!-- ko if: oConfig.hazmatLink-->
				<a class="global-modal hazmat__help" data-bind="html: oConfig.labels.hazmatHelpText, attr: { href: oConfig.hazmatLink }"></a>
			<!-- /ko -->
			<!-- ko if: dangerousRatio() !== 1 -->
				<div class="hazmat__ratio" data-bind="html: '(' + oConfig.labels.hazmatBoxRatio + ' ' + dangerousRatio() + ')'"></div>
			<!-- /ko -->
		</div>
	</script>

	<script type="text/html" id="catalog.softgoods">
		<!-- ko if: createSoftGoodsAuth -->
			<span data-bind="text: oConfig.labels.softgoods"></span>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.documents">
		<ul class="doc_downloads unstyled">
			<!-- ko if: $data.length > 0 -->
				<li data-bind="html: oConfig.labels.downloads"></li>
				<!-- ko foreach: $data -->
					<li data-bind="if: link() && name() ">
						<a data-bind="attr: { href: utils.buildImagePath(link()) }, text: name" target="_blank" ></a>
					</li>
				<!-- /ko -->
			<!-- /ko -->
		</ul>
	</script>

	<script type="text/html" id="catalog.product_account_history_short">
		<!-- ko if: oConfig.showProductHistory && oConfig.isLoggedIn && isOrdered -->
			<table class="tablesaw mini-prod-history smart-lists-container" >
				<tbody class="mini-prod-history__tbody" data-bind="if: isOrdered">
					<tr class="mini-prod-history__row total-qty-ordered">
						<td class="mini-prod-history__cat">Total Qty Ordered</td>
						<td class="mini-prod-history__data" data-bind="text: sumQty"></td>
					</tr>
					<tr class="mini-prod-history__row total-times-ordered">
						<td class="mini-prod-history__cat">Total Times Ordered</td>
						<td class="mini-prod-history__data" data-bind="text: orderCount"></td>
					</tr>
					<tr class="mini-prod-history__row most-recent-order-date">
						<td class="mini-prod-history__cat">Most Recent Order</td>
						<td class="mini-prod-history__data" data-bind="text: mostRecentOrderDate"></td>
					</tr>
				</tbody>
			</table>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.smart_lists">
		<!-- ko if: oConfig.showProductHistory && oConfig.isLoggedIn-->
			<h2 data-bind="html: oConfig.labels.productHistory"></h2>
			<div class="prod-history">
				<div class="prod-history__list">
					<!-- ko ifnot: accountHistory -->
						<p class="alert alert-warning">No additional information available.</p>
					<!-- /ko -->
					<!-- ko if: accountHistory -->
						<div class="clearfix prod-history__meta">
							<div class="pull-left" data-bind="if: accountHistory.accountName">
								<strong>Account:</strong>
								<span data-bind="html: accountHistory.accountName"></span>
							</div>
							<div class="pull-right" data-bind="if: accountHistory.lastUpdate">
								<strong>Last Updated:</strong>
								<span data-bind="text: accountHistory.lastUpdate"></span>
							</div>
						</div>
						<!-- ko template: { name: 'catalog.smart_lists_panels', data: accountHistory, if: accountHistory } --><!-- /ko -->
					<!-- /ko -->
				</div>
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.smart_lists_panels">
		<div class="row-fluid">

			<div class="span4">
				<table class="prod-history__table tablesaw order-stats" role="presentation">
					<thead class="panel-heading">
						<tr class="prod-history__row">
							<th class="prod-history__title" colspan="2">
								Order Stats
								<a class="prod-history__view-more btn btn-mini" data-bind="attr: { href: $parent.getSmartListLinkOrderStats($parent) }, visible: isOrdered">
									View Details <i class="icon-angle-right"></i>
								</a>
							</th>
						</tr>
					</thead>
					<tbody class="prod-history__tbody list-group">
						<!-- ko if: isOrdered -->
							<tr class="prod-history__row total-qty-ordered">
								<td class="prod-history__cat">Total Qty Ordered</td>
								<td class="prod-history__data" data-bind="text: sumQty"></td>
							</tr>
							<tr class="prod-history__row total-times-ordered">
								<td class="prod-history__cat">Total Times Ordered</td>
								<td class="prod-history__data" data-bind="text: orderCount"></td>
							</tr>
							<tr class="prod-history__row most-recent-order-date">
								<td class="prod-history__cat">Most Recent Order</td>
								<td class="prod-history__data" data-bind="text: mostRecentOrderDate"></td>
							</tr>
							<tr class="prod-history__row oldest-order-date">
								<td class="prod-history__cat">Oldest Order</td>
								<td class="prod-history__data" data-bind="text: oldestOrderDate"></td>
							</tr>

						<!-- /ko -->
						<!-- ko ifnot: isOrdered -->
							<tr class="prod-history__row previously-ordered">
								<td class="prod-history__cat">Previously Ordered</td>
								<td class="prod-history__data">No</td>
							</tr>
						<!-- /ko -->
					</tbody>
				</table>

			</div>

			<div class="span4">
				<table class="prod-history__table tablesaw invoice-stats" role="presentation">
					<thead class="panel-heading">
						<tr class="prod-history__row">
							<th class="prod-history__title" colspan="2">
							Invoice Stats
							<a class="prod-history__view-more btn btn-mini" data-bind="attr: { href: $parent.getSmartListLinkInvoiceStats($parent) }, visible: isInvoiced">
								View Details <i class="icon-angle-right"></i>
							</a>
							</th>
						</tr>
					</thead>
					<tbody class="list-group">
						<!-- ko if: isInvoiced -->
							<tr class="prod-history__row total-qty-invoiced">
								<td class="prod-history__cat">Total Qty Invoiced</td>
								<td class="prod-history__data" data-bind="text: sumInvoiceQty"></td>
							</tr>
							<tr class="prod-history__row total-times-invoiced">
								<td class="prod-history__cat">Total Times Invoiced</td>
								<td class="prod-history__data" data-bind="text: invoiceCount"></td>
							</tr>
							<tr class="prod-history__row most-recent-invoice-date">
								<td class="prod-history__cat">Most Recent Invoice</td>
								<td class="prod-history__data" data-bind="text: mostRecentInvoiceDate"></td>
							</tr>
							<tr class="prod-history__row oldest-invoice-date">
								<td class="prod-history__cat">Oldest Invoice</td>
								<td class="prod-history__data" data-bind="text: oldestInvoiceDate"></td>
							</tr>
							<tr class="prod-history__row amount-invoiced-mtd">
								<td class="prod-history__cat">Invoiced MTD</td>
								<td class="prod-history__data" data-bind="html: utils.formatMoney(sumInvoicedMtd)"></td>
							</tr>
							<tr class="prod-history__row amount-invoiced-last-month">
								<td class="prod-history__cat">Invoiced Last Month</td>
								<td class="prod-history__data" data-bind="html: utils.formatMoney(sumInvoicedLastMonth)"></td>
							</tr>
							<tr class="prod-history__row amount-invoiced-ytd">
								<td class="prod-history__cat">Invoiced YTD</td>
								<td class="prod-history__data" data-bind="html: utils.formatMoney(sumInvoicedYtd)"></td>
							</tr>
							<tr class="prod-history__row amount-invoiced-last-year">
								<td class="prod-history__cat">Invoiced Last Year</td>
								<td class="prod-history__data" data-bind="html: utils.formatMoney(sumInvoicedLastYear)"></td>
							</tr>
							<tr class="prod-history__row total-amount-invoiced">
								<td class="prod-history__cat">Total Invoiced</td>
								<td class="prod-history__data" data-bind="html: utils.formatMoney(sumInvoiced)"></td>
							</tr>
						<!-- /ko -->
						<!-- ko ifnot: isInvoiced -->
							<tr class="prod-history__row previously-invoiced">
								<td class="prod-history__cat">Previously Invoiced</td>
								<td class="prod-history__data">No</td>
							</tr>
						<!-- /ko -->
					</tbody>
				</table>

			</div>

			<div class="span4">
				<table class="prod-history__table tablesaw other-stats" role="presentation">
					<thead class="panel-heading">
						<tr class="prod-history__row">
							<th class="prod-history__title" colspan="2">Other Stats</th>
						</tr>
					</thead>
					<tbody class="list-group">
						<!-- ko if: viewedCount -->
							<tr class="prod-history__row times-viewed">
								<td class="prod-history__cat">Times Viewed</td>
								<td class="prod-history__data" data-bind="text: viewedCount"></td>
							</tr>
							<tr class="prod-history__row most-recent-view-date">
								<td class="prod-history__cat">Most Recent View</td>
								<td class="prod-history__data" data-bind="text: mostRecentViewDate"></td>
							</tr>
						<!-- /ko -->
						<tr data-bind="visible: oConfig.smartListShowFavorites" class="prod-history__row on-favorites-list">
							<td class="prod-history__cat" data-bind="html: oConfig.smartListFavoritesText"></td>
							<td class="prod-history__data" data-bind="text: isOnFavList ? 'Yes' : 'No'"></td>
						</tr>
						<tr data-bind="visible: oConfig.smartListShowInventoryWatch" class="prod-history__row on-inventory-watch">
							<td class="prod-history__cat" data-bind="html: oConfig.smartListInventoryWatchText"></td>
							<td class="prod-history__data" data-bind="text: isOnInventoryWatch ? 'Yes' : 'No'"></td>
						</tr>
						<tr data-bind="visible: oConfig.smartListShowAbandonedCart" class="prod-history__row in-abandoned-cart">
							<td class="prod-history__cat" data-bind="html: oConfig.smartListAbandonedCartText"></td>
							<td class="prod-history__data" data-bind="text: isInAbandonedCart ? 'Yes' : 'No'"></td>
						</tr>
					</tbody>
				</table>

			</div>
	</script>

	<script type="text/html" id="catalog.smart_lists_table">
		<table class="table table-bordered">
			<tr class="header-row order-stats">
				<th colspan="2">
					Order Stats
					<!-- ko if: isOrdered -->
						-
						<a data-bind="
							attr: {
								href: $parent.getSmartListLinkOrderStats($parent)
							}
						">
							View Details
						</a>
					<!-- /ko -->
				</th>
			</tr>
			<!-- ko if: isOrdered -->
				<tr class="total-qty-ordered">
					<td>Total Qty Ordered</td>
					<td data-bind="text: sumQty"></td>
				</tr>
				<tr class="total-times-ordered">
					<td>Total Times Ordered</td>
					<td data-bind="text: orderCount"></td>
				</tr>
				<tr class="most-recent-order-date">
					<td>Most Recent Order Date</td>
					<td data-bind="text: mostRecentOrderDate"></td>
				</tr>
				<tr class="oldest-order-date">
					<td>Oldest Order Date</td>
					<td data-bind="text: oldestOrderDate"></td>
				</tr>
			<!-- /ko -->
			<!-- ko ifnot: isOrdered -->
				<tr class="previously-ordered">
					<td>Previously Ordered</td>
					<td>No</td>
				</tr>
			<!-- /ko -->

			<tr class="header-row invoice-stats">
				<th colspan="2">
					Invoice Stats
					<!-- ko if: isInvoiced -->
						-
						<a data-bind="
							attr: {
								href: $parent.getSmartListLinkInvoiceStats($parent)
							}
						">
							View Details
						</a>
					<!-- /ko -->
				</th>
			</tr>
			<!-- ko if: isInvoiced -->
				<tr class="total qty invoiced">
					<td>Total Qty Invoiced</td>
					<td data-bind="text: sumInvoiceQty"></td>
				</tr>

				<tr class="total-times-invoiced">
					<td>Total Times Invoiced</td>
					<td data-bind="text: invoiceCount"></td>
				</tr>

				<tr class="most-recent-invoice-date">
					<td>Most Recent Invoice Date</td>
					<td data-bind="text: mostRecentInvoiceDate"></td>
				</tr>

				<tr class="oldest-invoice-date">
					<td>Oldest Invoice Date</td>
					<td data-bind="text: oldestInvoiceDate"></td>
				</tr>

				<tr class="amount-invoiced-mtd">
					<td>Amount Invoiced MTD</td>
					<td data-bind="html: utils.formatMoney(sumInvoicedMtd)"></td>
				</tr>

				<tr class="amount-invoiced-last-month">
					<td>Amount Invoiced Last Month</td>
					<td data-bind="html: utils.formatMoney(sumInvoicedLastMonth)"></td>
				</tr>

				<tr class="amount-invoiced-ytd">
					<td>Amount Invoiced YTD</td>
					<td data-bind="html: utils.formatMoney(sumInvoicedYtd)"></td>
				</tr>

				<tr class="amount-invoiced-last-year">
					<td>Amount Invoiced Last Year</td>
					<td data-bind="html: utils.formatMoney(sumInvoicedLastYear)"></td>
				</tr>

				<tr class="total-amount-invoiced">
					<td>Total Amount Invoiced</td>
					<td data-bind="html: utils.formatMoney(sumInvoiced)"></td>
				</tr>
			<!-- /ko -->
			<!-- ko ifnot: isInvoiced -->
				<tr class="previously-invoiced">
					<td>Previously Invoiced</td>
					<td>No</td>
				</tr>
			<!-- /ko -->

			<tr class="header-row other-stats">
				<th colspan="2">Other Stats</th>
			</tr>
			<!-- ko if: isOnFavList -->
				<tr class="on-favorites-list">
					<td>On Favorites List</td>
					<td>Yes</td>
				</tr>
			<!-- /ko -->
			<!-- ko if: viewedCount -->
				<tr class="times-viewed">
					<td>Times Viewed</td>
					<td data-bind="text: viewedCount"></td>
				</tr>
				<tr class="most-recent-view-date">
					<td>Most Recent View Date</td>
					<td data-bind="text: mostRecentViewDate"></td>
				</tr>
			<!-- /ko -->
			<!-- ko if: isOnInventoryWatch -->
				<tr class="on-inventory-watch">
					<td>On Inventory Watch</td>
					<td>Yes</td>
				</tr>
			<!-- /ko -->
			<tr class="in-abandoned-cart">
				<td>In Abandoned Cart</td>
				<td data-bind="text: isInAbandonedCart ? 'Yes' : 'No'"></td>
			</tr>
		</table>
	</script>

	<script type="text/html" id="catalog.detail_info">
		<dl class="prod-searchfields">
			<!-- ko template: 'catalog.sku_label' --><!-- /ko -->
			<!-- ko template: { name: 'catalog.searchfields', foreach: _.values(selectedProduct().searchfields) } --><!-- /ko -->
		</dl>
	</script>

	<script type="text/html" id="catalog.sku_label">
		<dt data-bind="html: oConfig.labels.sku"></dt>
		<dd itemprop="sku" data-bind="html: selectedProduct().sku"></dd>
	</script>

	<script type="text/html" id="catalog.searchfields">
		<!-- ko if: oConfig.showSearchFields && show() -->
			<dt class="prod-searchfields__label" data-bind="html: label"></dt>
			<dd class="prod-searchfields__value" data-bind="html: value"></dd>
		<!-- /ko -->
	</script>

	<script type="text/html" id="promotions.descriptions">
		<div class="promo-panel-container">
			<h4 class="promo-panel-heading" data-bind="text: title"></h4>
			<ul class="promo-panel-content" data-bind="foreach: descriptions">
				<li
					class="promo-panel"
					data-bind="
						text: description,
						css: {
							faded: $parent.selectedProduct().type !== 'parent' && !_.contains(targetKeys, $parent.selectedProduct().key())
						}
				">
				</li>
			</ul>
		</div>
	</script>

	<script type="text/html" id="catalog.configurator">
		<form id="frmAddToCart">
			<div id="configurator" data-bind="configurator: $data"></div>
		</form>
	</script>
	<script type="text/javascript">
		// The configurator markup cannot be placed directly in a template
		// because it can contain scripts and scripts cannot be nested. Instead,
		// a surrogate is used to allow the scripts to run and then its contents
		// are moved when the template is called. This means that each surrogate
		// can only be used once, and thus, only one product per page can
		// display a configurator form. However, this isn't a new limitation to
		// configurator since configurator uses generic IDs for all the elements
		// it creates.
		ko.bindingHandlers.configurator = {
			init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
				var product = ko.unwrap(valueAccessor());
				var data = product.configuratorEditData
				var $surrogate = $('#configurator_surrogate').detach();
				var $element = $(element);
				// Remove the scripts to prevent jQuery from running them again upon insertion.
				// Form builder does not allow disabling the use of form actions.
				$surrogate.find('script, .form-actions').remove();
				// In order to preserve bindings and jQuery data, the elements
				// are moved from the surrogate rather than copied. This won't
				// cause a reflow because the surrogate has `display: none`.
				$element.html($surrogate);
				$surrogate.children(':first-child').unwrap();

				//Stretchy.js is adding a style tag with height and width to text inputs and textareas.
				//This will remove those hardcoded heigths/widths but leave any "StyleOverride" props in place.
				_.each($element.find('textarea, input[type="text"]'), function(child){
					$(child).css('height','');
					$(child).css('width','');
				});

				if (data) {
					_.each(data.choices, function (choice) {
						var $inputs = $element.find('[name="' + choice.name + '"]');
						var answerVal;

						if (oConfig.configuratorUseAnswerIdNotName) {
							answerVal = choice.answer;
						} else {
							answerVal = choice.answerText;
						}

						if ($inputs.is(':checkbox, :radio')) {
							$inputs.filter('[value="' + answerVal + '"]').prop('checked', true);
						} else {
							$inputs.val(answerVal);
						}

						// Update display activators.
						$inputs.change();
					})

					product.selectedQty(data.qty);
				}

				runHook('afterBindingHandlersConfigInit', {product: product});
			},
			update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
				var product = ko.unwrap(valueAccessor());
				var $inputs = getInputs(product.key());

				// Trigger the input change after they have loaded so the price will calc on page load
				if ($inputs) {
					$inputs.change();
				}
			}
		};

		ko.bindingHandlers.validateQty = {
			init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

				$(element).on("click blur", function (event) {
					var min        = parseFloat($(element).attr('min'));
					var max        = parseFloat($(element).attr('max')) || 0;
					var step       = parseFloat($(element).attr('step'));
					var currentQty = parseFloat($(element).val());
					var newQty     = currentQty;
					var lowerBound;
					var minFound = false;
					var maxFound = false;
					var accessor = valueAccessor() || [];

					viewModel.updateQty = function(args){
						if(viewModel.orderDetailKey){
							viewModel.qty(args);
						}else{
							viewModel.selectedQty(args);
						}
					};

					if($(element).val() == ''){
						if((isActiveLayout('gallery') && event.type == 'blur') || event.type == 'click' ) {
							viewModel.updateQty(min);
							$(element).select();
							return;
						}
					}

					if(currentQty < min){
						newQty = min;
						viewModel.updateQty(newQty);
						invalidQtyNotification(bindingContext.$data)
						return;
					}

					if(currentQty > max && max > 0){
						newQty = max;
						viewModel.updateQty(newQty);
						invalidQtyNotification(bindingContext.$data)
						return;
					}

					var stepMod = parseFloat((currentQty - min) % step);
					if(stepMod != 0 && (!maxFound && !minFound)){
						newQty = Math.ceil((currentQty - min) / step) * step + min;

						viewModel.updateQty(newQty);
						invalidQtyNotification(bindingContext.$data)
						return;
					}

				});
			}
		};

		ko.bindingHandlers.validateQtyControlInput = {
			init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

				$(element).on("click blur", function (event) {
					var min        = parseFloat($(element).attr('min'));
					var max        = parseFloat($(element).attr('max')) || 0;
					var step       = parseFloat($(element).attr('step'));
					var currentQty = parseFloat($(element).val());
					var newQty     = currentQty;
					var lowerBound;
					var minFound = false;
					var maxFound = false;
					var accessor = valueAccessor() || allBindings().value;

					if(currentQty !== 0 && currentQty < min){
						newQty = min;
						accessor(newQty);
						return;
					}

					if(currentQty > max && max > 0){
						newQty = max;
						accessor(newQty);
						return;
					}

					var stepMod = parseFloat((currentQty - min) % step);
					if(stepMod != 0 && (!maxFound && !minFound)){
						if(ko.unwrap(valueAccessor())) {
							newQty = Math.ceil((currentQty - min) / step) * step + min;
						} else {
							newQty = Math.floor((currentQty - min) / step) * step + min;
						}
						accessor(newQty);
						return;
					}

				});
			}
		};

		ko.bindingHandlers.addModalHandler = {
			init: function(element, valueAccessor, allBindings){
				var bindings = allBindings.get('addModalHandler');
				modal.addCompletionHandler(bindings.element, bindings.handler);
			}
		};

		function getInputs(productKey) {
			var keyAttribute = 'data-configurator-product-key';
			// The container will vary based on whether this function is called
			// before or after the `catalog.configurator` template is used.
			var $container = $('#configurator_surrogate');
			if (!$container.length) $container = $('#configurator');
			var $dataElement = $container.find('[' + keyAttribute + ']');
			return $dataElement.attr(keyAttribute) === productKey ? $container.find(':input') : null;
		}

		function getPrice($inputs) {
			var price = 0;
			$inputs
				.filter(':visible:not(:disabled)')
				.find(':selected')
				.add($inputs.filter(':checked'))
				.each(function () {
					price += $(this).data('price') || 0;
				});

			return price;
		}

		(function () {

			window.buildConfiguratorPriceObservable = function (productKey) {
				var priceObservable = ko.observable(0);
				var $inputs = getInputs(productKey);

				if ($inputs) {
					priceObservable(getPrice($inputs));

					$inputs.change(function () {
						// modify the price for product configurator option
						runHook('modifyConfigOptionPrice', { 'inputs' : $inputs });

						var newPrice = getPrice($inputs);
						if (priceObservable() !== newPrice) priceObservable(newPrice);
					});
				}

				return priceObservable;
			};

			window.buildConfiguratorPostData = function (productKey) {
				var $inputs = getInputs(productKey);
				var postData = {};

				if ($inputs) {
					var ary = $inputs.filter(':not(:disabled)').serializeArray(); // can't exclude non-visible items; configurator uses them a lot!
					_.each(ary, function (datum) {
						if (datum.value) {
							if (postData.hasOwnProperty(datum.name)) {
								if(!Array.isArray(postData[datum.name])) {
									postData[datum.name] = [ postData[datum.name] ];
								}
								postData[datum.name].push(datum.value);
							} else {
								postData[datum.name] = datum.value;
							}
						}
					});
					postData['use_config_questions_' + productKey] = true;
				}
				return postData;
			};
		}());
	</script>
	<div id="configurator_surrogate" style="display: none">
		<div class="configurator">
		</div>
	</div>

	<script type="text/html" id="catalog.slideshow">
	</script>
	
		<script>
			var promotionMessages = ko.observableArray();
			ko.bindingHandlers.promoMessages = {
				preprocess: function (value, name, addBindingCallback) {
					if (oConfig.usePromos) {
						addBindingCallback('template', "{ name: 'promo.notification_bar', data: promotionMessages }");
					}
					return value;
				},
				init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
					if (oConfig.usePromos) {
						var productKeys = ko.toJS(_.pluck(valueAccessor(), 'key'));

						$.ajax({
							data: {
								ajax: 'promo-messages',
								productKeys: productKeys,
								modal: 1,
								modalaction: utils.getParameter("modalaction")
							},
							dataType: 'json'
						}).done(function (messages) {
							var existingLength = promotionMessages().length;
							var updateTicker = !existingLength;

							// Replace the entire array in one operation to prevent needlessly updating templates.
							_.partial(promotionMessages.splice, 0, existingLength).apply(promotionMessages, messages);
							// If there weren't previously any messages, the ticker needs to be activated.
							if (updateTicker) $(element).trigger('notification-center-added');

							$('body').addClass('notification-bar-active').append(element);
						});
					}
				}
			};
		</script>
		<script type="text/html" id="promo.notification_bar">
			<!-- ko template: {
				name: 'promo.notification_bar_markup',
				if: $data.length
			} --><!-- /ko -->
		</script>
		<script type="text/html" id="promo.notification_bar_markup">
			<div class="notification-center active">
				<div class="container">
					<div class="view-all-container" data-bind="if: $data.length > 1">
						<button type="button" class="close hide"><i class="icon-remove"></i></button>
						<a href="#" class="viewall">
							<span class="viewall-text">View all</span>
							<span class="badge" data-bind="text: $data.length"></span>
						</a>
					</div>
					<div class="notification-center-content">
						<ul class="unstyled" data-bind="foreach: $data">
							<li>
								<!-- ko if: $data.url -->
									<a data-bind="attr: { href: url }, text: text"></a>
								<!-- /ko -->
								<!-- text: $data.url ? '' : text -->
							</li>
						</ul>
					</div>
				</div>
			</div>
		</script>
<script>

	function invalidQtyNotification(data) {
		// change where key is derived from (different on payment page than catalog)
		var elementSelector = data.key ? '*[data-key="'+ data.key() + '"]' : '*[data-key="'+ data.orderDetailKey() + '"]';
		element = $(elementSelector);
		if ($(element).length){
			if(oConfig.preventATCInvalidQty) data.isQtyValid(false);
			$(element).popover('show').addClass('text-error') ;
			setTimeout(function () {
				$(element).popover('toggle').removeClass('text-error');

				// check to see if prop exists (doesn't on payment page)
				if(data.isQtyValid) {
					data.isQtyValid(true);
				}
			}, 3000 );
		}
	}

	function changeSort(data, event) {
		var sort = event.target.value;
		var sortField = sort.split('~')[0];
		var sortOrder = sort.split('~')[1];
		var url = utils.setParameter('sortby', sortField );
		url = utils.setParameter('sortorder', sortOrder, url );
		window.location = url;
	}

	function getSelectedSort() {
		if(utils.getParameter('sortby')){
			return decodeURI(utils.getParameter('sortby') + '~' + utils.getParameter('sortorder'));
		}else{
			return oConfig.searchConfig.defaultSort;
		}
	}

	function changeRpp(data, event) {
		var sUrl = utils.setParameter('rpp', event.target.value);
		sUrl = utils.setParameter('page', 1, sUrl);
		window.location = sUrl;
	}

	function getSelectedRpp() {
		if(utils.getParameter('favorites')){
			//force a single page for favorites lists.
			oConfig.searchConfig.rpp = 9999;
		}else{
			return utils.getParameter('rpp') || oConfig.searchConfig.rpp;
		}
	}

	function isActiveLayout(layout) {
		return getActiveLayout() === layout;
	}

	function getActiveLayout() {
		var layout = null;
		if(oConfig.pageName === 'pc_combined_results.asp'){
			if(utils.getParameter("modal") || utils.getParameter('queue_id')){
				layout = 'list';
			}else{
				var defaultLayout = oConfig.searchConfig.layout;
				var cookieLayout;
				var categoryLayout;
				if(oConfig.searchConfig.showLayout){
					cookieLayout = utils.getCookie('productLayout');
				}
				if(viewModel.category){
					if(viewModel.category.defaultView != ''){
						categoryLayout = viewModel.category.defaultView;
					}
				}
				//Priority = cookie > category > default
				layout = cookieLayout || categoryLayout || defaultLayout;
			}
		}else{
			layout = null;
		}
		return layout;
	}

	function getStartCount() {
		var startCount = (oConfig.searchConfig.page - 1) * oConfig.searchConfig.rpp + 1;
		return startCount;
	}

	function getEndCount() {
		var rpp = oConfig.searchConfig.rpp || oConfig.searchConfig.total;
		var endCount = Math.min(((oConfig.searchConfig.page - 1) * rpp) + rpp, oConfig.searchConfig.total);
		return endCount;
	}

	function maxPage() {
		return Math.ceil(oConfig.searchConfig.total / oConfig.searchConfig.rpp);
	}

	function setLayout(layout) {
		utils.setCookie('productLayout', layout);
		window.location.reload();
	}

	function getLayoutTemplate(data) {
		if(data.results().length == 0 && !data.category && oConfig.isUsingFacetedSearch){
			hideSidebar();
		}

		if(data.results().length == 0){
			hideSearchTools();
			return 'catalog.no_results'
		} else {
			return 'catalog.' + (getActiveLayout() || oConfig.searchConfig.layout) + '_view';
		}
	}

	function hideSidebar(){
		$('#catalog-sidebar').hide();
		$('.main-content').removeClass('span9');
	}

	function hideSearchTools(){
		$('#products_header, #products_footer, .hidesearchtools').hide()
	}

	function pagingNodes() {
		var page = oConfig.searchConfig.page;
		var labels = oConfig.searchConfig.labels;
		var maxPage = window.maxPage();

		nodes = [
			{
				if: page > 1 && labels.prevPage,
				page: page - 1,
				text: labels.prevPage
			},
			{
				if: page > 2,
				page: 1,
				text: labels.firstPage || 1
			},
			{
				if: page > 3,
				text: '&hellip;'
			},
			{
				if: page > 1,
				page: page - 1
			},
			{
				if: true,
				text: page,
				page: page
			},
			{
				if: page < maxPage,
				page: page + 1
			},
			{
				if: page < maxPage - 2,
				text: '&hellip;'
			},
			{
				if: page < maxPage - 1,
				page: maxPage,
				text: labels.maxPage || maxPage
			},
			{
				if: page < maxPage && labels.nextPage,
				page: page + 1,
				text: labels.nextPage
			},
		];

		return _.compact(_.map(nodes, function (node) {
			return node.if ?
				{
					page: node.page,
					text: node.text || node.page
				} : null;
		}));
	}

	function getATCModalSize(){
		if(oConfig.usePromos){
			return '';
		}else{
			return 'small';
		}
	}

	function isTextSelected(input) {
			if (typeof input.selectionStart == "number") {
					return input.selectionStart == 0 && input.selectionEnd == input.value.length;
			} else if (typeof document.selection != "undefined") {
					input.focus();
					return document.selection.createRange().text == input.value;
			}
	}
	
	function setOptionHTML(optionElement, item) {
		var itemText = item ? item.name : '-- Select Option --';
		ko.applyBindingsToNode(optionElement, {html: itemText}, item);
	}
	
	function setOptionHtmlFromName(optionElement, item) {
		var itemText = item ? item.name : '-- Select Option --';
		ko.applyBindingsToNode(optionElement, {html: itemText}, item);
	}

	function setChildOptionDisable(field, optionElement, item) {
		function isInvalidChildOption(children, options, field, item) {
			return ko.computed(function () {
				var match = {};
				_.forEach(options, function (option) {
					// Don't unwrap unnecessary observables.
					if (option.field === field) return;
					var selected = option.selectedOption();
					if (selected) match[option.field] = selected.option;
				});
				match[field] = item.option;
				return !_.find(children, match);
			});
		}

		if (item && ko.unwrap(viewModel.mainProduct).children() && ko.unwrap(viewModel.mainProduct).children().length) {
			var obs = isInvalidChildOption(
				ko.unwrap(viewModel.mainProduct).children(),
				ko.unwrap(viewModel.mainProduct).childSelectors(),
				field,
				item
			);
			var itemText = item ? item.option : '-- Select Option --';
			ko.applyBindingsToNode(optionElement, {disable: obs, html: itemText}, item);
		} else {
			var itemText = item ? item.option : '-- Select Option --';
			ko.applyBindingsToNode(optionElement, {html: itemText}, item);
		}
	}

	function addToCartWithValidation(products, event, parentKey) {
		var invalidQtyIndex = _.findIndex(products, function(product) {return !product.isQtyValid()});
		var addingFromPayment = utils.getParameter('modal') == '1' && (pageType == 'favlist' || pageType == 'bulkadd' || pageType == 'invoice' || pageType == 'salesorder');
		var pendingProducts = _.filter(products, function(product){
			return !product.showQuickAtc() && !product.isInCart();
		})

		//If the total quantity selected on the page is <=0 then display an error message
		var iTotalQtyToAtc = _.filter(products,function(product) {return product.selectedProduct().selectedQty() > 0; }).length;
		if (iTotalQtyToAtc <= 0) {
			var data = { products: products, event: event };
			utils.openModal({
				body	: oConfig.atcInvalidQtyTemplate,
				size	: getATCModalSize(),
				title	: oConfig.labels.invalidQtyTitle
			}, data);
			return;
		}

		if(oConfig.preventATCInvalidQty && invalidQtyIndex != -1) {
			utils.scrollTo('[data-key="' + products[invalidQtyIndex].key() + '"');
		} else {
			utils.addToCart(
				_.filter(products, function (product) {
					return product.selectedProduct().selectedQty() > 0;
			}), undefined, parentKey);
		}

	}

	function replaceSavedCartKeywordWithGlobal(sLabel) {
		return sLabel.replace('<cart>', "Quote");
	}

	$(function () {
		
		runHook('modifyConfigSettings', oConfig); //called here so that the hooks are all registered first.

		ko.bindingHandlers.raty = {
			init: function () {
				return { controlsDescendantBindings: true };
			},
			update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
				var value = ko.unwrap(valueAccessor());
				var isRated = value != null;
				var $element = $(element);
				// This is no longer necessary since we are displaying ratings all the time,
				// plus it was setting inline style of 'block' when element needed 'inline-block' - jonr 2016-10-25
				// $element.toggle(isRated);

				if (isRated) {
					var options = typeof value === 'object' ? value : { score: value };
					_.defaults(options, {
						path: utils.buildImagePath('/gfx/').split('?')[0],
						space: false,
						readOnly: true,
						width: 90,
						hints: oConfig.ratingNames
					});
					$(element).html($('<div>').raty(options));
				}
			}
		};

		ko.applyBindings();

		runHook('afterApplyBindings', { });
	});

	function setPromoDescriptionTitleText(promoDescription) {
		var productPromotions = "";

		_.forEach(promoDescription, function (descriptions) {
			productPromotions += descriptions.description + '\n';
		});
		return productPromotions;
	}

	function setSelectedQty() {
		if(!!viewModel.mainProduct && !!ko.unwrap(viewModel.mainProduct).configuratorEditData && !!ko.unwrap(viewModel.mainProduct).configuratorEditData.qty) {
			ko.unwrap(viewModel.mainProduct).selectedProduct().selectedQty(ko.unwrap(viewModel.mainProduct).configuratorEditData.qty);
			return false;
		}
		//Preload the previous quantity when using the bulk order tools
		if(utils.getParameter('queue_id') || oConfig.searchConfig.pageType == 'salesorder' || oConfig.searchConfig.pageType == 'invoice'){
			return true;
		}
		if (oConfig.pageName === "pc_combined_results.asp") {
			return getActiveLayout() !== 'list' || oConfig.showListViewATC;
		}
		else if(oConfig.pageName === "pc_product_detail.asp") {
			return viewModel.mainProduct.childDisplayType() !== 'input-qty' && viewModel.mainProduct.childDisplayType() !== 'exploded-view' && viewModel.mainProduct.childDisplayType() !== 'matrix-all' && !viewModel.mainProduct.configuratorEditData;
		}
		else {
			return true;
		}
	}

	function setSelectedCartOptionAnswer(question) {
		if(viewModel.mainProduct && ko.unwrap(viewModel.mainProduct).configuratorEditData) {
			var editAnswer = ko.unwrap(viewModel.mainProduct).configuratorEditData.choices.filter(function(item) {
				return item.question === question.q_key();
			});

			if(editAnswer && editAnswer.length) {
				var editAnswerText = editAnswer[0].answerText;

				if(question.type() === 'select') {
					questionAnswer = question.answers().filter(function(answer) {
						return ko.unwrap(answer.value) === editAnswerText;
					});

					if(!!questionAnswer.length) {
						question.selectedAnswer(ko.unwrap(questionAnswer[0].value));
					}
				} else {
					question.selectedAnswer(editAnswerText);
				}
			}
		}
	}

	//AJAX Call to remove item from favorites list.
	function fncRemoveItem (sProdKey , product) {
		jQuery.ajax({
			url: 'pc_combined_results.asp',
			data: 'ajax=removefavitems&modal=1&p_key=' + sProdKey + '&fl_key=' + utils.getParameter('fl_key'),
			type: 'GET',
			dataType: 'text',
			success: function () {
				//remove from viewmodel
				viewModel.results.remove(product);
			}
		});
	}

	//If no products can be added to cart in list view then do not display the ATC button at the bottom of the page.
	function showAddAllToCart() {
		var productsShowingAtc = _.filter(viewModel.results(), function(result) { return result.showQuickAtc(); }).length;
		return productsShowingAtc > 0;
	}

	var pageType = "";
	var defaultHomeLink = "default.asp";
	var breadcrumbKey = "";
	var breadcrumbObj = utils.getStoredBreadcrumbs() || {breadcrumbs:{}};
	var activeBreadcrumb = breadcrumbObj.breadcrumbs[breadcrumbKey];
	
		$(function() {
			if(pageType == 'category'){
				var useDynamicBreadcrumbs = true;
				//Check the stored breadcrumbs for dyanmic urls
				_.each(activeBreadcrumb, function(crumb){
					if(useDynamicBreadcrumbs && crumb.link.indexOf('pc_id') > -1){
						//Dynamic link found, blank out the active breadcrumb and fall back to the DM breadcrumbs.
						useDynamicBreadcrumbs = false;
						console.log('Invalid Breadcrumb Found');
					}
				});
				if(!useDynamicBreadcrumbs){
					activeBreadcrumb = [];
				}
			}
		});

		$(document).on('click', '#prod_listings .detail_link', function(){
			var productKey = $(this).data('key');
			var productName = $(this).attr('title');

			var defaultBreadcrumb = [{ name: 'Home', link: window.location.pathname + window.location.search }];
			if(window.location.search != '' && window.location.pathname == '/pc_combined_results.asp'){
				if(utils.getParameter('queue_id')){
					homeName = 'Bulk Add Queue';
				}else{
					homeName = 'Search Results';
				}
				defaultBreadcrumb = [{ name: homeName, link: window.location.pathname + window.location.search }];
			}
			var productBreadcrumb = activeBreadcrumb || defaultBreadcrumb;
			productBreadcrumb.push({
				name: productName,
				link: ''
			});

			var breadcrumbObj = utils.getStoredBreadcrumbs() || {breadcrumbs: {}};
			breadcrumbObj.breadcrumbs[productKey] = productBreadcrumb;
			utils.setStoredBreadcrumbs(breadcrumbObj);
		});

		$(document).on('click', '.category-listings a', function(){
			var categoryKey = $(this).data('key');
			var categoryName = $(this).attr('title');
			var categoryLink = $(this).attr('href');

			var categoryBreadcrumb = activeBreadcrumb;
			categoryBreadcrumb.push({
				name: categoryName,
				link: categoryLink
			});

			var breadcrumbObj = utils.getStoredBreadcrumbs() || {breadcrumbs: {}};
			breadcrumbObj.breadcrumbs[categoryKey] = categoryBreadcrumb;
			utils.setStoredBreadcrumbs(breadcrumbObj);
		});

		$(document).on('click', '#category-window a, #header__prodcat a, .linkset .prodcat a', function(){
			if($(this).data('key')){
				var parentName = [];
				var parentHref = [];
				if($(this).data('parent-name') ){
					parentName = $(this).data('parent-name').split('|');
					parentHref = $(this).data('parent-href').split('|');
				}
				var contentKey = $(this).data('key');
				var categoryName = $(this).text();
				var categoryUrl = $(this).attr('href');

				var parents = [];
				for( i = 0; i < parentName.length ; i++ ){
					parents.push({
						name: parentName[i],
						link: parentHref[i]
					});
				}

				var home = [];
				home.push(
					{
						name: 'Home',
						link: defaultHomeLink
					}
				);
				var breadcrumb = home.concat(parents);
				var breadcrumbObj = utils.getStoredBreadcrumbs() || {breadcrumbs: {}};
				breadcrumbObj.breadcrumbs[contentKey] = breadcrumb;
				utils.setStoredBreadcrumbs(breadcrumbObj);
			}
		});
	

	var oConfig = {
		pageName: "signin.asp",
		mainProductKey: "",
		isModal: false,
		atcSplashTemplate: 'catalog.atc_splash',
		atcInvalidQtyTemplate : 'catalog.atc_invalid_qty',
		savedCartPopupTemplate: 'catalog.saved_cart_select_popup',
		ratingNames: ['Bad', 'Poor', 'Good', 'Very Good', 'Excellent'],
		formValidationKey: "",
		isUsingFacetedSearch: false,
		overrideCartKey: "" || "" || "" || "7C743E237AD14B3F9C9E236A7665CEC7",
		activeBreadcrumb: activeBreadcrumb,
		showCloneInstanceLink: false,

		sessionData : {
			sc_id : "7C743E237AD14B3F9C9E236A7665CEC7",
			sessionKey : "D79FD399538C4F9E919FD94A412B0F0C",
			storefrontUrl : "https://coresite.cimproduction.com",
			orderfrontUrl : "https://coresite.cimproduction.com",
			cdnUrl: "https://d3ccrbl9fhkqmr.cloudfront.net",
			isSuperUserSession : false
		},

		detailConfig : {
			productKey                 : '',
			useAdvancedTabs            : false,
			useRelatedProducts         : true,
			useSecondRelatedProducts   : true,
			useAlsoBoughtProducts      : false,
			useAddOnProducts           : false,
			useRecentlyViewedProducts  : false,
			useAliases                 : false,
			useSkuDisplay              : false,
			selectChildProductOnLoad   : true,
			tabLayoutMode              : "gallery",
			numberOfProductTabs        : "8",
			pageLayoutMode             : "gallery",
			showDocuments              : true,
			inputQtyLinkToChild        : false,
			globalUnitPriceDecimalPlaces : 2,
			gridRowClass               : "",
			gridLeftColumnClass        : "",
			gridRightColumnClass       : "",
			showProductDescriptionTop  : false,
			showSoftGoodAuthorizations : false,
			showDescription            : true,
			showMainImage              : true,

			labels : {
				relatedProducts        : "Related Products",
				secondRelatedProducts  : "Additional Products",
				alsoBoughtProducts     : "Customers Who Bought This Also Bought...",
				readReviews            : "Read Reviews",
				inputQty               : "Options",
				inputQtyATCLabel       : "Add to Cart Below <i class=\"icon-arrow-down\"></i>",
				recentlyViewedProducts : "Recently Viewed",
				pricesStartingAt       : "Starting at "
			}
		},

		searchConfig : {
			pageType                   : '',
			page                       : 0,
			total                      : 0,
			showAtc                    : true,
			hideAtcShowInv             : false,
			showLayout                 : true,
			layout                     : "gallery" || 'gallery',
			showRpp                    : true,
			rppOptions                 : [25,50,100],
			showSort                   : true,
			productSort                : {
		"field"     : "p.sku",
		"direction" : "asc",
		"display"   : "SKU (a-z)"
	},
			productSortOptions         : [{
		"field"     : "p.sku",
		"direction" : "asc",
		"display"   : "SKU (a-z)"
	},{
		"field"     : "p.sku",
		"direction" : "desc",
		"display"   : "SKU (z-a)"
	},{
		"field"     : "p.nm",
		"direction" : "asc",
		"display"   : "Name (a-z)"
	},{
		"field"     : "p.nm",
		"direction" : "desc",
		"display"   : "Name (z-a)"
	}],
			showDownload               : false,
			gridListViewRowClass       : "",
			gridListViewATCColumnClass : "",
			showDescription            : true,
			showCategoryDescription    : true,
			showThumb                  : true,
			requireAddOnSelection      : false,

			labels : {
				layout                    : "",
				sort                      : "Sort by",
				rpp                       : "per page",
				firstPage                 : "",
				maxPage                   : "",
				prevPage                  : "<i class=\"icon-angle-left\"></i> Prev",
				nextPage                  : "Next <i class=\"icon-angle-right\"></i>",
				favListRemoveColumnHeader : "",
				searchResultsHeader       : "<count> results for <keyword>",
				pricesStartingAt          : "Starting at ",
				galleryView               : "<i class=\"icon-th\"></i> Gallery",
				listView                  : "<i class=\"icon-list-ul\"></i> List",
				inventoryWatchLinkText    : "<i class=\"icon-eye-open\"></i> Watch"
			}
		},

		formAction : "https://coresite.cimproduction.com/i_i_add_to_cart.asp",
		isLoggedIn : false,
		showChildrenSelection: false,
		allowQuickAdd: true,

		usePromos                : true,
		useIdp                   : true,
		useUom                   : (false || false),
		useSalesUom              : false,
		useMultiUomMultiCurrency : false,
		useMinimumQuantity       : true,
		useMaximumQuantity       : true,
		useQuantityIncrement     : true,
		useReviews               : false,
		allowAddAnonymousReviews : false,
		get allowAddReviews()
			{
				return this.isLoggedIn || this.allowAddAnonymousReviews;
			},
		useBreaks                : false,
		useBreaksTable           : false,
		priceBreaksTableHeader   : "Quantity Price Breaks",
		useSavedCarts            : false,
		useTaxExempt             : false,
		showInventoryWatch       : false,
		showEmailFriend          : true,
		showFavLink              : true,
		showRFQLink              : false,
		showProductHistory		   : true,
		showProductHistoryResults: true,
		showWarehouses           : true,
		showProdYouSave          : true,
		allowWarehouseSelection  : true,
		useWarehousesTable       : false,
		defaultWarehouse         : "",
		hazmatLink               : "help/about-dangerous-goods",
		allowChildATC            : true,
		showListViewATC          : true,
		showNameCol              : true,
		showImgCol 				 : true,
		preventATCInvalidQty 	 : false,
		showZeroPriceMessage	 : false,
		zeroPriceMessage		 : "Pricing is not currently available on this product. If purchased you will be contacted with pricing and updated order totals before processing your order.",
		showPricingOrderEntry    : true,
		configuratorUseAnswerIdNotName: false,
		useCartOptions : false,
		showSearchFields: false,

		labels : {
			pic                              : "Pic",
			price                            : "Price",
			sku                              : "SKU",
			uom                              : "Unit:",
			description                      : "Description",
			reviews                          : "Reviews",
			productHistory                   : "Product History",
			qty                              : "QTY",
			breaks                           : "Qty Pricing",
			inventoryWatch                   : "Add to Watch List",
			warehouses                       : "Warehouses",
			inventoryStatus                  : "Status",
			downloads                        : "Downloads:",
			suggestedPrice                   : "List Price",
			nameCol                          : "Name",
			imgCol                          : "Image",
			emailFriend                      : "Email a Friend",
			favLink                          : "Add to Favorites",
			step                             : "Qty Increment",
			minQty                           : "Min Qty",
			minQtyPopover 					 : "Minimum Qty: <min_qty>",
			maxQty                           : "Max Qty",
			showCartLink                     : "Proceed to Cart",
			continueShoppingLink             : "Continue Shopping",
			hazmat                           : "<span class=\"label label-warning\"><i class=\"fas fa-exclamation-triangle\"></i> Dangerous</span>",
			hazmatBoxRatio                   : "Box Ratio:",
			hazmatHelpText                   : "What's this?",
			softgoods						 : "Purchasing this item provides a digital file that will be delivered upon placing the order.",
			invalidQtyText                   : "You have to enter a valid quantity in at least one of the products on this page to add them to this quote.",
			invalidQtyTitle                  : "Missing Quantity",
			youSaveLabel                     : "You Save",
			removeFavLink                    : "Remove From Favorites",
			rfqLinkLabel                     : "Request a Custom Quote",

			savedCarts			: "Quote",
			savedCartsLabels 	: {
				addToSavedCart                   : replaceSavedCartKeywordWithGlobal("Add to <cart>"),
				itemText	                     : replaceSavedCartKeywordWithGlobal("Product"),
				modalHeader                      : replaceSavedCartKeywordWithGlobal("Add Item to <cart>"),
				modalCreateNew                   : replaceSavedCartKeywordWithGlobal("Create a new <cart>"),
				modalCreateNewSaveButton         : replaceSavedCartKeywordWithGlobal("Save"),
				modalCreateNewInputPlaceholder   : replaceSavedCartKeywordWithGlobal("<cart> Name"),
				modalExisting                    : replaceSavedCartKeywordWithGlobal("Add to Existing <cart>"),
				modalConfirmationHeader          : replaceSavedCartKeywordWithGlobal("Added to <cart>"),
				modalConfirmationSubHeader       : replaceSavedCartKeywordWithGlobal("Added to <cart>"),
				modalConfirmationViewButton      : replaceSavedCartKeywordWithGlobal("View <cart>"),
				modalConfirmationManageButton    : replaceSavedCartKeywordWithGlobal("Manage <cart>s"),
				modalConfirmationCloseButton     : replaceSavedCartKeywordWithGlobal("Close")
			},

			addToCart     : "<i class=\"icon-shopping-cart\"></i> Add",
			addToCartList : "<i class=\"icon-shopping-cart\"></i> Add to Cart",
			updateCartItem: "Update",
			taxExempt     : "Tax Exempt?",

			selectOptionsLabel : "Select options<i class=\"icon-angle-right icon-fixed-width\"></i>",

			noResults : "",

			productNotFound : "Product Not Found.",
			categoryNotFound : "Category Not Found.",

			averageRating    : "Average Rating",
			reviewSignInText : "Sign in to add a review",
			reviewsAddText   : "Add a Review",
			cloneInstanceLink: "",
			cloneInstanceTitle:"",
		},

		mapBehaviorMessages : {
			showMessage            : "Call for Price",
			requireLoginMessage    : "<div class=\"text-small muted\"><a class=\"global-modal\" data-size=\"small\" data-backdrop=\"static\" title=\"Sign in to Your Account\" href=\"security_logon.asp?autopage=/signin.asp?autopage=%2Fsitemap.asp&target=_parent\">Sign in</a> to see price</div>",
			requireAtcMessage      : "<div class=\"text-small muted\">View price in cart</div>",
			requireLoginAtcMessage : "<div class=\"text-small muted\"><a class=\"global-modal\" data-size=\"small\" data-backdrop=\"static\" title=\"Sign in to Your Account\" href=\"security_logon.asp?autopage=/signin.asp?autopage=%2Fsitemap.asp&target=_parent\">Sign in</a> to add to cart</div>",
			requireLoginOrAtcMessage: "<div class=\"text-small muted\"><a class=\"global-modal\" data-size=\"small\" data-backdrop=\"static\" title=\"Sign in to Your Account\" href=\"security_logon.asp?autopage=/signin.asp?autopage=%2Fsitemap.asp&target=_parent\">Sign in</a> or add to cart to see price</div>"
		},

		flags : [
			{
				link  : "content/page-1.asp",
				title : "Page 1",
				pic   : "flag1_n.png",
				thumb : "flag1_t.png"
			},
			{
				link  : "",
				title : "",
				pic   : "flag2_n.png",
				thumb : "flag2_t.png"
			},
			{
				link  : "",
				title : "",
				pic   : "flag3_n.png",
				thumb : "flag3_t.png"
			},
			{
				link  : "",
				title : "",
				pic   : "flag4_n.png",
				thumb : "flag4_t.png"
			}
		],

		childOptionList                        : [],
		childSkuMatch                          : "",
		defaultImage                           : "no-image.png" || 'no-image.png',
		noImagePath                            : "images/no-image.png" || 'images/no-image.png',
		displayDroplistPlaceholdersForLazyLoad : false,
		centerRecentlyViewed                   : false,
		smartListShowFavorites                 : true,
		smartListFavoritesText                 : "On Favorites List?",
		smartListShowInventoryWatch            : false,
		smartListInventoryWatchText            : "On Inventory Watch?",
		smartListShowAbandonedCart             : false,
		smartListAbandonedCartText             : "In Abandoned Cart?",
		t_analytics                            : "none",
		t_tracking_company             		   : "",
		t_tracking_id                          : "",
		t_gtm                                  : true,
		t_gtm_id                               : "GTM-N4SKHRM",
		t_gtm_add_to_cart_event_name           : "EEaddToCart",
	};

	oConfig.usingFlags = oConfig.flags.reduce(function(anyFlagSet, flag) {
		var flagSet = flag.pic || flag.thumb
		return flagSet || anyFlagSet
	}, false);

</script>
</div>

<div class="cart-templates-scripts">

<script type="text/javascript">

    addTimer("start of ko model");
    $( document ).ready(function() {

        if('signin.asp' == 'payment.asp' ){
            $(document).on('hidden', '#global_modal', function () {
                if( $('#handle-modal-exit').val() == 'true'){
                    $('#handle-modal-exit').val(false);
                    viewModel.genericModalComplete();
                }
            });
        }
        addTimer("cart_templates: document.ready");

    });

    function emptyHandler(){}

    function scrollToSection(id) {
         $('html, body').animate({
            // subtracting body padding-top accounts for toolbars with absolute
            // position, such as the SU bar
            scrollTop: $(id).offset().top - parseInt($("body").css('padding-top'))
         }, 300,
        function(){
            $('html, body').clearQueue();
        });
    }

    function reloadPage() {
        viewModel.processing(true);
        location.reload();
	}

	function sendError(message) {
		if (window['insightRUM']) {
			insightRUM.rawErrors.push(["Error", sPageName, 1, 1, new Error(message.substring(0,149))]);
		}
	}

    function buildContinueShoppingUrl(){
        var url = ofConfig.continueShopPage;
        if(ofConfig.guestLoggedIn){
            url = utils.setParameter('action','logout',url);
        }
        return url;
    }

    function isValidRequestedDate(date) {
		try {
			isBusinessDay = businessDaySettings[1][""].work_days_of_week == undefined || businessDaySettings[1][""].work_days_of_week.indexOf(date.getDay()+1) > -1;
			isHoliday = businessDaySettings[1][""].holiday_dates != undefined && businessDaySettings[1][""].holiday_dates.indexOf(moment(date).format("MM/DD/YYYY")) > -1;
			if(isBusinessDay && !isHoliday) {
				return true;
			} else {
				return false;
			}
		} catch (error) {
			sendError("isValidRequestedDate: " + error.message);
			return true;
		}
    }

    function calculateAdjustedLeadTimeDays(effectiveOrderDate, leadTimeDays) {
        /*
            EJ - 2016-11-10 - adding 1 initially due to JS interpreting the date from the db as UTC date
                              when in fact it is a local date at midnight.  This causes the date
                              in JS to be the day before at 7pm (-5) or 8pm (-4) depending on time
                              of year.
                              Since we are only really concerned with the day, we can add one to
                              compensate for this.
        */
        var adjustedLeadTimeDays = leadTimeDays;

        /* EJ - 2016-11-10 - This if block helps mitigate when the cuttoff time has passed, but the
                             effective_order_date on the SelectedShipVia has not be recalced by the
                             ordering object yet.  It essentially checks the cutoff if the effective_order_date
                             is today.  Otherwise, there is no need to calculate it.
        */
        if(moment(effectiveOrderDate).date() <= moment().date()) {
            var currentDateTime = new Date();
            var currentUTCSeconds = currentDateTime.getUTCSeconds() + (60 * currentDateTime.getUTCMinutes()) + (60 * 60 * currentDateTime.getUTCHours());

            if(currentUTCSeconds > businessDaySettings[1][""].utc_cutoff_time_seconds) {
                adjustedLeadTimeDays += 1;
            }
        }

        var startingDate = moment();

        for(var i = 1; i < adjustedLeadTimeDays + 1; i++) {
            if(!isValidRequestedDate(startingDate.add(1, "days").toDate())) {
                adjustedLeadTimeDays += 1;
            }
        }

        return adjustedLeadTimeDays;
    }

    function autoAllocateItems() {
        if((!viewModel.useMultiShipEditUI()) || (viewModel.shipments().length === 1
            && viewModel.shipments()[0].shipTo().key() != ""
            && viewModel.shipments()[0].shipTo().key() != null)) {
                if(viewModel.shipments()[0].details().length === 0) {
                    viewModel.moveAllItemsToShipment(viewModel.shipments()[0]);
                }
        }
    }

    //This div is contained in the SU dashboard bar.
    utils.setActiveQuote = function (orderKey) {
        if(orderKey != ofConfig.SessionOrderKey) {
             jQuery.ajax({
                url: 'payment.asp' + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=setActiveQuote&quote_id=' + orderKey + '&randomnum=' + new Date().getTime()
                , cache: false
                , success: function(data,status,request){

                }
                , error: function(data) {
                    alert('Error posting Recurring Order Settings');
                }
                , complete: function(data) {
                }
            });
        }
    }

    utils.removeActiveQuote = function (bStartNewQuote) {
        utils.setActiveQuote('');
        if(bStartNewQuote){
            window.location = 'payment.asp' + (ofConfig.isModal ? '?modal=1' : '');
        }else{
            $('.active-quote-message').hide();
        }
    };

    var orderInfoPostUrl = 'payment.asp'; //'https://' + window.location.hostname + window.location.pathname;
    var orderInfoPostApiUrl = "/ordering/";
    var countries = [];
    var newCustomer = false;
    var viewModel;
    var order;

    function addAddressHandler() {
        viewModel.allocateShipments(false);
        apiGetShippingAddresses();
    }

    function changeAddressFromFinder(response, object){
        console.log(response);
        var address = new addressInfo({ key: response.sha_key.value, state: '', city: '', zipCode: '', country: '', name: response.sha_key_disp.value, address1: '', global: 0 });
        object.shipTo(address);
    }

    function getAddressOptFields(){
        var addressOptFields = [];
        for(i=1; i <= 5; i++){
            if(ofConfig['showAddressOpt'+i]){
                addressOptFields.push(i);
            }
        }
        return addressOptFields;
    }

    function apiGetShippingAddresses(editedKey) {
        $.ajax({
            url: orderInfoPostUrl + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=apiGetShippingAddresses',
            success: function(data) {
                // viewModel.shippingAddresses = processShippingAddresses(JSON.parse(data))();
                // viewModel.shippingAddresses.notifySubscribers();
                var newVarForTesting = processShippingAddresses(JSON.parse(data))();
				var editedShaKey = editedKey || '';
				var bFound;
                _.each(newVarForTesting, function(newItem){
                    _.each(viewModel.shippingAddresses(),function(oldItem){
                        if(editedShaKey != ''){
                            if(oldItem.key() == editedShaKey && newItem.key() == editedShaKey){
                                oldItem.name(newItem.name());
                                oldItem.phone(newItem.phone());
                                oldItem.address1(newItem.address1());
                                oldItem.address2(newItem.address2());
                                oldItem.address3(newItem.address3());
                                oldItem.address4(newItem.address4());
                                oldItem.address5(newItem.address5());
                                oldItem.city(newItem.city());
                                oldItem.state(newItem.state());
                                oldItem.zipCode(newItem.zipCode());
                                oldItem.opt1(newItem.opt1());
                                oldItem.opt2(newItem.opt2());
                                oldItem.opt3(newItem.opt3());
                                oldItem.opt4(newItem.opt4());
                                oldItem.opt5(newItem.opt5());
                                return false;
                            }
                            bFound = true;
                        }else{
                            bFound = false;
                            if(oldItem.key() == newItem.key()){
                                bFound = true;
                                return false;
                            }
                        }
                    });
                    if(!bFound && editedShaKey == ''){
                        viewModel.shippingAddresses.push(ko.mapping.fromJS(newItem, shippingAddressMappingOptions));
                        return false;
                    }
                });
                viewModel.availableAddresses = viewModel.shippingAddresses;
            },
            error: function(){
                alert('error getting shipping addresses');
            }
        });
    }

    var shippingAddressMappingOptions = {
        create: function(options) {
            var address = new addressInfo(options.data);
            address.summaryLine = ko.computed(function() {
                var lineText = '';

                function separator(separatorText) {
                    return lineText === '' ? '' : separatorText;
                }

                function addField(field, separatorText) {
                    if(!separatorText) { separatorText = ', '}
                    lineText += field ? separator(separatorText) + field : '';
                }

                addField(address.name());
                addField(address.company());
                addField(address.attention());
                addField(address.firstName());
                addField(address.lastName(), address.firstName() ? ' ' : '');
                addField(address.address1());
                addField(address.address2());
                addField(address.address3());
                addField(address.address4());
                addField(address.address5());
                addField(address.global());
                addField(address.city());
                addField(address.state());
                addField(address.zipCode(), ' ');
                addField(address.country());

                return lineText;
            });
            return address;
        }
    }

    function getNewAddress() {
        return {
            name: "",
            firstName: "",
            lastName: "",
            company: "",
            attention: "",
            address1: "",
            address2: "",
            address3: "",
            address4: "",
            address5: "",
            country: "USA",
            city: "",
            state: "",
            county: "",
            zipCode: "",
            phone: "",
            email: "",
            global: "0",
            opt1: "",
            opt2: "",
            opt3: "",
            opt4: "",
            opt5: "",
            key: utils.createGuid()
        }
    }

    function getShippingFromBilling() {
        var newAddress = JSON.parse(ko.toJSON(viewModel.Account));

        newAddress.firstName = viewModel.Customer().firstName();
        newAddress.LastName = viewModel.Customer().LastName();
        newAddress.Email = viewModel.Customer().Email();
        newAddress.Phone = viewModel.Customer().Phone();
        newAddress.Name = "";
        newAddress.Attention = viewModel.Customer().firstName() + ' ' + viewModel.Customer().LastName();
        newAddress.key = utils.createGuid();

        return newAddress;
    }

    function getNewShipment() {
        return new Shipment({
            Key: utils.createGuid(),
            SelectedShipVia: {},
            ShipViaChoices: [],
            Details: [],
            LeadTimeDays: null,
            ShipTo: getNewAddress(),
            Comments: "",
            availableAddresses: shippingAddresses
        });
    }

    function generateRefId(){
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth()+1; //January is 0!
        var yyyy = today.getFullYear();
        var rand = Math.floor(Math.random() * 1000000)

        if(dd<10) {
            dd='0'+dd
        }

        if(mm<10) {
            mm='0'+mm
        }

        today = yyyy+mm+dd+'-'+rand;
        return today;
    }

    var StateChoice = function(code, name) {
        var self = this;

        var choice = {};
        choice["code"] = code;
        choice["name"] = name;

        ko.mapping.fromJS(choice, {}, self);
    }

    var detailLineInstanceSort = function (a, b) {
            var aInstance = a.instance();
            var bInstance = b.instance();
            var aParentId = a.parentProductID().trim();
            var bParentId = b.parentProductID().trim();

            if(aInstance == bInstance) {
                return (aParentId < bParentId) ? -1 : (aParentId > bParentId) ? 1 : 0;
            } else {
                return (aInstance < bInstance) ? -1 : 1;
            }
    }

    var shipmentDetailsInstanceSort = function(a, b) {
        return detailLineInstanceSort(a.orderDetail, b.orderDetail);
    }

    var addressInfo = function(addressData, addressType) {
        var self = this;

        if(!addressData) {
            addressData = getNewAddress();
        }

        // Order JSON returns isGlobalAddress while the rest of the template loads in data relying on global
        if('isGlobalAddress' in addressData && !('global' in addressData)){
            addressData.global = addressData.isGlobalAddress;
        }
        
        addressData.addressType = ko.observable(addressType || 'shipping');

        ko.mapping.fromJS(addressData, {}, self);

        if(!self.state()) {
            self.state(undefined);
        }

        for(var prop in self) {
            if(self.hasOwnProperty(prop) && typeof self[prop] === 'function') {
                if(self[prop]() === null || self[prop]() === 'null') {
                    self[prop]('');
                }
            }
        }

        self.address1.extend({ required: true });
        self.country.extend({ required: true });
        self.city.extend({ required: true });
        self.state.extend({ required: ofConfig.bRequireStateForShipping });
        self.zipCode.extend({ required: ofConfig.bRequireZIPCodeForShipping });

        if(!self.country()) {
            self.country("USA");
        }

        self.stateChoices = ko.observableArray();

        self.editing = ko.observable(false);

        self.loadStates = function() {
            countries.forEach(function(country) {
                if(country.iso3 === self.country()) {
                    self.stateChoices(country.states);
                }
            });
            if(!self.country()){
                self.stateChoices.removeAll();
            }
        }

        self.country.subscribe(function() {
            self.loadStates();
        });

        self.loadStates();
    }

    var detailMap = function(detailLine, shipment, order) {
        var self = this;
        self.detailLine = detailLine;
        self.shipment = shipment;
        self.totalOrderQty = ko.computed(function() { return detailLine.qty(); });
        self.qtyToShip = ko.observable();
        self.qtyInShipment = ko.observable(function() {
                self.qtyToShip(self.shipment.details().reduce(function(prev, curr, index, arr) {
                    if(curr.orderDetailId() == detailLine.orderDetailKey()) {
                        return prev + Number(curr.qtyToShip());
                    } else {
                        return prev;
                    }
                }, 0));
                return self.qtyToShip();
            }()
        );

        self.qtyInAllShipments = ko.computed(function() {
            var theKey = self.shipment.key();
            var allShipmentsTotal = order.shipments().reduce(function(runningTotal, individualShipment) {
                var individualShipmentTotal = individualShipment.details().reduce(function(runningSubTotal, detail) {
                    if(detail.orderDetailId() == detailLine.orderDetailKey()) {
                        return runningSubTotal + Number(detail.qtyToShip() || 0);
                    } else {
                        return runningSubTotal;
                    }
                }, 0);
                return runningTotal += individualShipmentTotal;
            }, 0);

            var currentShipmentTotal = self.shipment.details().reduce(function(runningSubTotal, detail) {
                if(detail.orderDetailId() == detailLine.orderDetailKey()) {
                    return runningSubTotal + Number(detail.qtyToShip() || 0);
                } else {
                    return runningSubTotal;
                }
            }, 0)

            var otherShipmentsTotal = allShipmentsTotal - currentShipmentTotal;

            return otherShipmentsTotal + Number(self.qtyToShip() || 0);
        });

        self.unallocatedQty = ko.computed(function() { return self.detailLine.qty() - self.qtyInAllShipments(); });
        self.toggleItemSelect = ko.computed({
            read: function() {
                return this.qtyToShip() > 0;
            },
            write: function(isChecked) {
                if(isChecked){
                    this.qtyToShip(1);
                } else {
                    this.qtyToShip(0);
                }
            }
        }, self);

        runHook('detailLineModelBottom', { self: self, detailLine: self });
    };

    var Shipment = function(shipmentData) {
        var self = this;
        ko.mapping.fromJS(shipmentData, {
            shipTo : shippingAddressMappingOptions,
            shipViaChoices : {
                create: function(options) {
                    if(options.data == null) {
                        return ko.mapping.fromJS([]);
                    } else {
                        return ko.mapping.fromJS(options.data);
                    }
                }
            },
            selectedShipVia : {
                create: function(options) {
                    if(options.data == null) {
                        return ko.mapping.fromJS({requestDate: "0001-01-01T00:00:00"});
                    } else {
                        return ko.mapping.fromJS(options.data);
                    }
                }
            },
            details: {
                create: function(options) {
                    options.data.orderDetail.configuratorJson = options.data.orderDetail.configuratorJson ? JSON.parse(options.data.orderDetail.configuratorJson) : {};
                    if(options.data.orderDetail.configuratorJson && options.data.orderDetail.configuratorJson.choices) {
                        options.data.orderDetail.configuratorJson.choices = options.data.orderDetail.configuratorJson.choices.sort(function(a, b) {
                            if(a.pos == b.pos) {
                                return 0;
                            }
                            return a.pos < b.pos ? -1 : 1;
                        });
                    }
                    if(options.data.orderDetail.configuratorJson) {
                        options.data.orderDetail.configuratorJson.configType = options.data.orderDetail.configuratorJson.configType || 'configurator';
                    }
                    options.data.orderDetail.parentProductID  = options.data.orderDetail.parentProductID.trim() || '';
                    options.data.orderDetail.editing = false;

                    return ko.mapping.fromJS(options.data);
                }
            }
        }, self);

        self.details().forEach(function(detail) {
            var detailLine = detail.orderDetail;
            detailLine.instanceChildren = self.details().filter(function(item) {
                                            return item.orderDetail.instance() == detailLine.instance() && item.orderDetail.parentProductID().trim() != '' && item.orderDetail != detailLine;
                                        }).map(function(item) { return item.orderDetail; }) || [];

            var mainProductArray = self.details().filter(function(item) {
                                            return item.orderDetail.instance() == detailLine.instance() && item.orderDetail.removeType() == 'instance';
                                        });
            var mainProduct = mainProductArray.length > 0 ? mainProductArray[0].orderDetail : detailLine;

            var mainProductQty = mainProduct.qty();

            detailLine.instanceUnitPrice = ko.observable(self.details().reduce(function(current, item) {
                if(item.orderDetail.instance() == detailLine.instance()) {
                    //This IF block is attempting to account for calculating the unit price on "nested" configurator lines.  Any other product type should fall into
                    //  The else block so it just pulls the quantity from the od lines.
                    //TODO:  Account for configurator products AND split by address as this calculation will likely not work in that scenario.
                    //       In this scenario, it should use the extended quantity on the shipment not the one from the OD line.
                    if(item.orderDetail.parentProductID().trim() != '' && item.orderDetail.removeType() != 'instance' && item.orderDetail.removeType() != 'OD_Key') {
                        return current += ((item.orderDetail.priceBeforeAdjustment() || item.orderDetail.price()) * item.qtyToShip()) / mainProductQty;
                    } else {
                        return current += (item.orderDetail.priceBeforeAdjustment() || item.orderDetail.price());
                    }
                } else {
                    return current;
                }
            },0));

            detailLine.instanceUnitPriceDisplay = ko.computed(function(){
                return utils.formatMoney(detailLine.instanceUnitPrice());
            });

            detailLine.instanceExtPrice = ko.observable(self.details().reduce(function(current, item) {
                if(item.orderDetail.instance() == detailLine.instance()) {
                    return current += (item.orderDetail.priceBeforeAdjustment() || item.orderDetail.price()) * item.qtyToShip();
                    // return current += item.orderDetail.extTotal();
                } else {
                    return current;
                }
            },0));
        });

        self.availableAddresses = shippingAddresses;

        self.shipTo = ko.observable(self.shipTo);

        self.availableAddresses().forEach(function(address,index){
            if(!self.shipTo()){
                self.shipTo(address);
                return false;
            }
            if(address.key() == self.shipTo().key()){
                self.shipTo(address);
            }
        });

        self.earliestShipDate = ko.observable(
            function() {
                if(self.selectedShipVia && self.selectedShipVia.effectiveOrderDate) {
                    var adjustedLeadTimeDays = calculateAdjustedLeadTimeDays(self.selectedShipVia.effectiveOrderDate(), self.leadTimeDays());
                    return moment(self.selectedShipVia.effectiveOrderDate()).add(adjustedLeadTimeDays, "days").format("MM/DD/YYYY");
                } else {
                    return moment(new Date(self.ExpectedShipDate)).format("MM/DD/YYYY");
                }
            }()
        );

        self.requestedShipDate = ko.observable(
            function() {
                if(self.selectedShipVia && self.selectedShipVia.requestDate()) {
                    if(self.selectedShipVia.requestDate() >= self.earliestShipDate()) {
                        return moment(new Date(self.selectedShipVia.requestDate())).format("MM/DD/YYYY");
                    } else {
                        return self.earliestShipDate();
                    }
                } else {
                    if(self.selectedShipVia && self.selectedShipVia.effectiveOrderDate) {
                        var adjustedLeadTimeDays = calculateAdjustedLeadTimeDays(self.selectedShipVia.effectiveOrderDate(), self.selectedShipVia.leadTimeDays());
                        return moment(self.selectedShipVia.effectiveOrderDate()).add(adjustedLeadTimeDays - 1, "days").format("MM/DD/YYYY");
                    } else {
                        return moment(new Date(self.ExpectedShipDate)).format("MM/DD/YYYY");
                    }
                }
            }()
        );

        if(self.selectedShipVia && self.selectedShipVia.shippingAccountId){
            self.selectedShipVia.shippingAccountId = ko.validatedObservable(self.selectedShipVia.shippingAccountId() || '').extend({ required: true, message: 'Please select a shipping account.'});

            self.selectedShipVia.shippingAccountId.subscribe(function(shippingAccountKey){
                var postData = {};
                var orderShipViaDetails = [];

                orderShipViaDetails = [
                    {
                        "osvd_key" : self.selectedShipVia.orderShipViaDetailKey(),
                        "sa_id" : shippingAccountKey
                    }
                ]

                postData =
                {
                    "Tables": [
                        {
                            "TableName" : "orders_ship_via_details",
                            "TableKeyField" : "osvd_key",
                            "UserKeyField" : "osvd_key",
                            "UserKeyIsPrimaryKey" : "True",
                            "Data" : orderShipViaDetails
                        }
                    ]
                };

                postLogicJsonAjax(postData, true);
            });
        }else{
            self.selectedShipVia = {};
            self.selectedShipVia.shippingAccountId = ko.observable('');
            self.selectedShipVia.collectShippingAccount = ko.observable(false);
            self.selectedShipVia.name = ko.observable('');
            self.selectedShipVia.description = ko.observable('');
            self.selectedShipVia.total = ko.observable(0);
            self.selectedShipVia.shipViaChoiceID = ko.observable('');
            self.selectedShipVia.sv_ref_id = ko.observable('');
        };

        if(self.shipViaChoices && self.shipViaChoices().length > 0){
            self.selectedShipViaChoice = ko.observable(self.shipViaChoices().find(function(choice) {
                return (choice.shipViaChoiceKey() == self.selectedShipVia.shipViaChoiceID() || choice.shipViaRefID() == self.selectedShipVia.sv_ref_id());
            }) || self.shipViaChoices()[0]);
        }else{
            self.selectedShipViaChoice = ko.observable();
        }

        self.shipToValid = ko.computed(function() {
            return ko.validatedObservable(self.shipTo()).isValid();
        });

        self.saveShipToAddress = function(shipment) {

            var shipmentArray = [];

            var details = shipment.details().map(function(map, index, array) {
                return {
                    orderDetailId : map.orderDetailId(),
                    qtyToShip: map.qtyToShip()
                }
            });

            var shipmentInfo = {
                "Key": shipment.key(),
                "ShipmentId": shipment.key(),
                "ShipTo": {
                    key         : shipment.shipTo().key(),
                    name        : shipment.shipTo().name(),
                    company     : shipment.shipTo().company(),
                    attention   : shipment.shipTo().attention(),
                    address1    : shipment.shipTo().address1(),
                    address2    : shipment.shipTo().address2(),
                    address3    : shipment.shipTo().address3(),
                    address4    : shipment.shipTo().address4(),
                    address5    : shipment.shipTo().address5(),
                    city        : shipment.shipTo().city(),
                    state       : shipment.shipTo().state(),
                    zipCode     : shipment.shipTo().zipCode(),
                    county      : shipment.shipTo().county(),
                    country     : shipment.shipTo().country(),
                    email       : shipment.shipTo().email(),
                    firstName   : shipment.shipTo().firstName(),
                    lastName    : shipment.shipTo().lastName(),
                    phone       : shipment.shipTo().phone(),
                    global      : shipment.shipTo().global(),
                    opt1        : shipment.shipTo().opt1(),
                    opt2        : shipment.shipTo().opt2(),
                    opt3        : shipment.shipTo().opt3(),
                    opt4        : shipment.shipTo().opt4(),
                    opt5        : shipment.shipTo().opt5()
                },
                "Details": details
            };

            shipmentArray.push(shipmentInfo);

            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)),
                success: function(data) {
                    autoAllocateItems();
                    self.showShippingAddressEdit(false);
                },
                error: function() {
                    alert('error saving shipping address');
                }
            }

            postInfo(postOptions, 'updateShipToAddress', shipment.key());
        };

        self.setShippingToBilling = function(shipment) {
            var newAddress = getShippingFromBilling();
            shipment.shipTo(ko.mapping.fromJS(newAddress,shippingAddressMappingOptions));
            shipment.saveShipToAddress(shipment);
        }

        self.showShippingAddressEdit = ko.computed({
            read: function() {
                if(!self.shipToValid()) {
                    self.shipTo().editing(true);
                }
                return self.shipTo().editing();
            },
            write: function(newValue) {
                if(!newValue && self.shipToValid()) {
                    self.shipTo().editing(false);
                } else {
                    self.shipTo().editing(true);
                }
            }
        });

        // self.EarliestShipDate.extend();
        // self.RequestedShipDate.extend({ min: self.EarliestShipDate });
        // self.RequestedShipDate.extend({ min: { params: self.EarliestShipDate, message: "The earliest ship date available is {0}" } });

        self.detailsMap = ko.observableArray([]);

        self.valid = ko.computed(function() {
            return self.shipToValid() && self.details().length > 0; // && self.RequestedShipDate.isValid();
        });

        self.itemsSelected = ko.computed(function() {
            return self.details().length > 0;
        });

        self.selectItemsComplete = function(shipment) {

            var shipmentArray = [];

            var lineMappings = shipment.detailsMap().map(function(map, index, array) {
                return {
                    OrderDetailId : map.detailLine.orderDetailKey(),
                    QtyToShip: map.qtyToShip()
                }
            });

            var shipmentInfo = {
                Key: shipment.key(),
                ShipmentId: shipment.key(),
                Details: []
            };
            shipmentInfo.Details = lineMappings;
            shipmentArray.push(shipmentInfo);

            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)),
                error: function() {
                    alert('error saving item list on shipment');
                }
            }

            postInfo(postOptions, 'updateShipToAddress');

            $('#modal_add_prods[tabindex="-1"]:hidden').remove()
            $('#modal_add_prods').modal('hide');
        };

        self.selectedShipViaChoice.subscribe(function(newShipViaChoiceValue) {
            var shipViaChoiceKey = newShipViaChoiceValue.shipViaChoiceKey();
            var shipmentKey = self.key();

            var postOptions = {
                url: orderInfoPostUrl + '?ajax=true&pageaction=setShipmentShipVia&o_key=' + viewModel.orderKey()  + '&shipViaChoiceKey=' + shipViaChoiceKey + '&shipmentKey=' + shipmentKey,
                error: function() {
                    alert('error setting Shipping Method');
                }
            }

            postInfo(postOptions, 'setShipmentShipVia');

        });

        self.comments.subscribe(function(newComment) {

            var shipmentCommentPostData = {};

            var shipmentInfo = [{
                "os_key": self.key(),
                "comments": newComment
            }];

            shipmentCommentPostData =
            {
                "Tables": [
                    {
                        "TableName"           : "order_shipments",
                        "TableKeyField"       : "os_key",
                        "UserKeyField"        : "os_key",
                        "UserKeyIsPrimaryKey" : "True",
                        "Data"                : shipmentInfo
                    }
                ]
            };

            postLogicJsonAjax(shipmentCommentPostData);
        });

        self.requestedShipDate.subscribe(function(newRequestedShipDate) {

            if (!(newRequestedShipDate instanceof Date) || isNaN(newRequestedShipDate.valueOf())) {
                console.log('requestedShipDate is not a date');
                return;
            }

            var postOptions = {
                data: "shipmentId=" + encodeURIComponent(self.key()) + "&requestedShipDate=" + encodeURIComponent(moment(newRequestedShipDate).format('MM/DD/YYYY')),
                error: function() {
                    alert('error setting shipment requested ship date');
                }
            }

            postInfo(postOptions, 'setRequestedShipDate');
        });

        self.details().forEach(function(thisLine) {
            thisLine.hasChildProducts = ko.observable(function() {
                return self.details().filter(function(outerLine) {
                    return outerLine.orderDetail.instance() == thisLine.orderDetail.instance()
                            && thisLine.orderDetail.removeType() != 'instance'; // main product has removeType of instance
                }).length > 1;
            }());

            thisLine.orderDetail.hasParentInCart = ko.observable(function() {
                return self.details().filter(function(outerLine) {
                    return outerLine.orderDetail.orderDetailKey() != thisLine.orderDetail.orderDetailKey()
                            && outerLine.orderDetail.instance() == thisLine.orderDetail.instance()
                            && outerLine.orderDetail.removeType() == 'instance';
                }).length > 0;
            }());
        });

        if(ofConfig.useAccountDefaultShipVia && self.shipViaChoices && self.shipViaChoices().length > 0) {
            var filteredChoice = self.shipViaChoices().find(function(choice) {
                return choice.shipViaChoiceKey() == ofConfig.accountDefaultShipViaKey ||
                choice.shipViaRefID() == ofConfig.accountDefaultShipViaCode
            });

            if(filteredChoice) {
                self.shipViaChoices([ filteredChoice ]);
            }
        }

        self.shipTo.subscribe(function(shipTo) {
            if(viewModel && viewModel.setShipTo) {
                viewModel.setShipTo(self, shipTo);
            }
        })

        runHook('shipmentModelBottom', { self: self, shipmentData: shipmentData });
    }

    var Customer = function(customerData) {
        var self = this;

        ko.mapping.fromJS(customerData, {}, self);

        self.firstName.extend({ required: true });
        self.lastName.extend({ required: true });
        self.email.extend({ email: { message: 'A valid email address is required.', params: true }, required: { message: 'A valid email address is required.', params: true} });
        self.phone.extend({ required: true });
    }

    /*
    var Account = function(accountData) {
        var self = this;

        ko.mapping.fromJS(accountData, {
            create: function(options) {
                return new addressInfo(options.data);
            }
        }, self);

        if(!self.Country()) {
            self.Country('USA');
        }

        self.Company.extend({ required: true });
        self.Address1.extend({ required: true });
        self.Country.extend({ required: true });
        self.City.extend({ required: true });
        if(!self.State()) {
            self.State("");
        }
        self.State.extend({ required: true });
        self.ZipCode.extend({ required: true });
    }
    */

    var Order = function(orderData) {
        addTimer("start order mapping");
        var self = this;

        self.activeAjaxRequestCount = ko.observable(0);

        ko.mapping.fromJS(orderData, {
            detailLines : {
                create: function(options) {
                    options.data.configuratorJson = options.data.configuratorJson ? JSON.parse(options.data.configuratorJson) : {};
                    options.data.parentProductID  = options.data.parentProductID.trim() || '';
                    options.data.editing = false;
                    return ko.mapping.fromJS(options.data);
                }
            },
            orderActions : {
                create: function(options) {
                    if(options.data) {
                        if(!options.data.hasOwnProperty('showPaymentMethods')) {
                            options.data.showPaymentMethods = true;
                        }
                    }
                    return ko.mapping.fromJS(options.data);
                }
            },
            shipments : {
                create: function(options) {
                    return new Shipment(options.data);
                }
            },
            customer : {
                create: function(options) {
                    return options.data ? new Customer(options.data) : {};
                }
            },
            account : {
                create: function(options) {
                    return new addressInfo(options.data);
                }
            },
            paymentMethod : {
                create: function(options) {
                    if(options.data == null || options.data == '') {
                        return ko.mapping.fromJS({
                            paymentMethodKey: "",
                            paymentType: "",
                        });
                    } else {
                        options.data.paymentType = (options.data.paymentType || "").toLowerCase();
                        return ko.mapping.fromJS(options.data);
                    }
                }
            },
            vaultedPayment : {
                create: function(options) {
                    if(options.data == null) {
                        return ko.mapping.fromJS({
                            key: "",
                            vaultKey: "",
                            nickName: "",
                            nameOnCard: "",
                            cardType: "",
                            expMonth: 0,
                            expYear: 0,
                            first2: "0",
                            last4: "0",
                            address1: "",
                            address2: "",
                            city: "",
                            state: "",
                            zip: "",
                            country: "",
                            status: true,
                            merchantId: "",
                            customerId: "",
                            accountId: "",
                            gatewayInfoDirty: false,
                            accountLast4: "",
                            achAccountType: "",
                            bankName: "",
                            routingLast4: "",
                            type: "",
                            customerProfileId: ""
                        });
                    } else {
                        return ko.mapping.fromJS(options.data);
                    }
                }
            },
            roRunDate : {
                update: function(options) {
                    //Quick fix to hide invalid expiration.
                    //ToDo: update to check for other "invalid" dates.
                    date = new Date(options.data);

                    var isValid = date instanceof Date && !isNaN(date);
                    if(moment(date).format("MM/DD/YYYY") == '01/01/0001' || moment(date).format("MM/DD/YYYY") == '01/01/2001'){
                        isValid = false;
                    }

                    if(!isValid) {
                        return moment().format("MM/DD/YYYY");
                    } else {
                        return moment(date).format("MM/DD/YYYY");
                    }
                }
            },
            roRecCase : {
                update: function(options) {
                    if(!options.data) {
                        return 'month';
                    } else {
                        return options.data;
                    }
                }
            },
            roRecQty : {
                update: function(options) {
                    if(!options.data || options.data == 0) {
                        return 1;
                    } else {
                        return options.data;
                    }
                }
            },
            'ignore': ["errorMessages"]
        }, self);

        self.showCredits = ko.observable(false);
        self.allowQtyControls = ko.observable(false);

        self.detailLines().forEach(function(detailLine) {
            // We can't debounce/trottle an observable
            // so we add a computed to track qty changes.
            // We use this in a subscription to call
            // update cart to update qty change in bulk atc
            // to avoid loading the qty change without posting
            // and updating the entire order model (for perf)
            detailLine.qtyTracker = ko.computed(function() {
                return detailLine.qty();
            }).extend({throttle: 500});
            detailLine.qtyTracker.subscribe(function (newQty) {
                self.postQtyUpdate();
            }, detailLine);
            
            detailLine.workerPriceTracker = ko.computed(function() {
                return detailLine.price();
            }).extend({throttle: 500});
            detailLine.workerPriceTracker.subscribe(function (newQty) {
                self.setWorkerPriceOverride(detailLine);
            }, detailLine);

            detailLine.workerQtyLimitsTracker = ko.computed(function() {
                return {
                    removeType: detailLine.removeType(),
                    minQty: detailLine.minQty(),
                    maxQty: detailLine.maxQty(),
                    qtyIncrement: detailLine.qtyIncrement()
                };
            }).extend({throttle: 500});
            detailLine.workerQtyLimitsTracker.subscribe(function (newValue) {
                self.setWorkerQtyLimits(detailLine);
            });

            detailLine.instanceChildren = self.detailLines().filter(function(item) {
                                            return item.instance() == detailLine.instance() && item != detailLine;
                                        }) || [];

            var mainProduct = self.detailLines().filter(function(item) {
                                            return item.instance() == detailLine.instance() && item.removeType() == 'instance';
                                        })[0] || detailLine;

            var mainProductQty = mainProduct.qty();

            detailLine.instanceUnitPrice = ko.observable(self.detailLines().reduce(function(current, item) {
                if(item.instance() == detailLine.instance()) {
                    if(item.parentProductID().trim() != '' && item.removeType() != 'instance') {
                        return current += item.extTotal() / mainProductQty;
                    } else {
                        return current += item.price();
                    }
                } else {
                    return current;
                }
            },0));

            detailLine.instanceUnitPriceDisplay = ko.computed(function(){
                return utils.formatMoney(detailLine.instanceUnitPrice());
            });

            detailLine.instanceExtPrice = ko.observable(self.detailLines().reduce(function(current, item) {
                if(item.instance() == detailLine.instance()) {
                    return current += item.extTotal();
                } else {
                    return current;
                }
            },0));
        });

        self.needToChoosePromos = ko.observable();

        self.paymentMethodSelected = ko.observable(function() {
                return typeof self.paymentMethod.paymentType == 'function';
            }()
        );

        self.termsAgreement = ko.observable(function() {
                return self.legalResponse() == 'agreed';
            }()
        );

        //self.detailLines.sort(detailLineInstanceSort);

        self.shipments.sort(function(left, right) {
            return left.position() == right.position() ? 0 : (left.position() < right.position() ? -1 : 1);
        });

        self.processing = ko.observable(false);
        self.populatingShippingAddresses = ko.observable(false);
        self.availableShippingAddresses = ko.observableArray([]);
        self.newCouponCode = ko.observable("");
        self.newGiftCertificate = ko.observable("");
        if(!self.errorMessages) {
            self.errorMessages = ko.observableArray();
        };
        // self.orderPlaced = ko.observable(false);

        self.orderPlaced = ko.computed(function() {
            return self.completed()
        });

        self.Customer = ko.validatedObservable(self.Customer);
        self.Account = ko.validatedObservable(self.Account);

        self.shippingAddresses = shippingAddresses;

        self.addressTypes = function(){
            var addressTypes = [];
            addressTypes.push({
                label: ofConfig.addressBookLabel,
                global: '0'
            });
            if(ofConfig.useLocalPickup){
                addressTypes.push({
                    label: ofConfig.localPickupLabel,
                    global: '1'
                })
            }
            return addressTypes;
        };

        self.defaultShaKey = function() {
            sShaKey = sDefaultShaKey;
            if (sShaKey == ''){
                sShaKey = self.shippingAddresses()[0].sha_key;
            }
            return sShaKey;
        }
        self.billingSectionValid = ko.computed(function () {
            return self.Customer.isValid() && self.Account.isValid();
        });

        self.toggleShowBillingEdit = function() {
            if(self.showBillingEdit()) { // && newCustomer) {
                var postData = new CreateCustomerPost(self);
                self.postBillingUpdate(postData);
            } else {
                self.showBillingEdit(!self.showBillingEdit());
            }
        };

        self.postBillingUpdate = function(postData) {

            var postUrl = orderInfoPostUrl + '?o_key=' + viewModel.orderKey() + '&origin=bill-ship';
            var dataString;
            var keyCount = 0;

            $.each(postData, function(key, value) {
                keyCount += 1;

                if(keyCount > 1) {
                    dataString += "&"
                }
                dataString += key + "=" + encodeURIComponent(value);
            });

            var postOptions = {
                url: postUrl,
                type: "POST",
                data: dataString,
                success: function(data) {
                    self.showBillingEdit(!self.showBillingEdit());
                },
                error: function() {
                    alert('error posting billing update');
                }
            }

            postInfo(postOptions, '', 'checkout_shipping');
        }

        self.editingBilling = ko.observable(false);
        self.showBillingEdit = ko.computed({
            read: function() {
                if(!self.billingSectionValid()) {
                    self.editingBilling(true);
                }
                return self.editingBilling(); // && !self.billingSectionValid();
            },
            write: function(newValue) {
                if(!newValue && self.billingSectionValid()) {
                    self.editingBilling(false);
                } else {
                    self.editingBilling(true);
                }
            }
        });

        self.moveAllItemsToShipment = function(shipment) {
            self.processing(true);

            var shipmentArray = [];

            var lineMappings = self.detailLines().map(function(map, index, array) {
                return {
                    OrderDetailId : map.orderDetailKey(),
                    QtyToShip: map.qty()
                }
            });

            var shipmentInfo = {
                Key: shipment.key(),
                ShipmentId: shipment.key(),
                Details: []
            };

            self.shipments().forEach(function(otherShipment) {
                if(otherShipment.key() != shipment.key()) {
                    shipmentArray.push({
                        key: otherShipment.key(),
                        ShipmentId: otherShipment.key(),
                        Delete: true
                    });
                }
            });

            shipmentInfo.Details = lineMappings;
            shipmentArray.push(shipmentInfo);

            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)),
                error: function() {
                    alert('error moving all products to shipment');
                },
                complete: function() {
                    self.processing(false);
                }
            }

            postInfo(postOptions, 'updateShipToAddress');

            $('#modal_add_prods[tabindex="-1"]:hidden').remove()
            $('#modal_add_prods').modal('hide');
        };

        self.isOverLineLimit = ko.observable(checkLineLimit(self));

        function checkLineLimit(vm){
            //use the alternate ui (showcart.asp) when over the line limit threshold
            // Don't allow this to happen if using user create shipments since the showcart page doesn't support
            // Split shipping.
            if(oConfig.allowUserCreatedShipments){
                return false;
            }else if (ofConfig.useTooManyLinesRestriction && vm.detailLines().length >= parseInt(ofConfig.tooManyLinesQuantity)){
                return true;
            }else{
                return false;
            }
        }

        self.isMinimumOrderTotalMet = ko.observable(checkOrderTotal(self));
        //moved definition to global scope

        self.shippingComplete = ko.observable(isShippingComplete());

        function isShippingComplete(){
            if ( self.completed() || self.lifecycleStage() == 'cancelled') {
                return true;
            }

            // force step 2 if there are no lines on the order.
            if (self.detailLines().length == 0){
                return false;
            }

            // force step 3 if the lines exceed the limit.
            if (self.isOverLineLimit()){
                return true;
            }

            // force step 2 if any shipments are missing an address.
            _.each(self.shipments(),function(shipment){
                if(!shipment.shipTo().key()){
                    return false;
                }
            });

            if(!self.isMinimumOrderTotalMet()){
                utils.setCookie(self.orderKey() + '-step', '2');
            }

            if(utils.getCookie(self.orderKey()+'-step') == undefined){
                if(ofConfig.defaultShippingSectionOpen){
                    utils.setCookie(self.orderKey() + '-step', '2');
                }else{
                    utils.setCookie(self.orderKey() + '-step', '3');
                }
            }

            if (utils.getCookie(self.orderKey() + '-step') == '2'){
                return false;
            }else{
                return true;
            }
        };

        self.shipmentsComplete = ko.observable(false || self.completed());

        self.shipmentsSectionsValid = ko.computed(function() {
            var result = true;
            self.shipments().forEach(function(shipment) {
                if(!shipment.valid() || (shipment.shipTo && shipment.shipTo().editing())) {
                    result = false;
                }
            });
            return result;
        });

        self.toggleShowShippingEdit = function() {
            self.showShippingEdit(!self.showShippingEdit());
            if(!self.showShippingEdit()) {
                scrollToSection('#checkout_summary');
            }
        };

        self.moveItemToNewShipTo = function(item){
            self.itemShipToMap().push({
                orderDetailKey: item.orderDetailKey,
                instance: ko.observable(item.instance()),
                key: ko.observable(item.orderDetailKey),
                qty: ko.observable(item.qtyIncrement() || 1),
                qtyControlledFrom: ko.observable(item.qtyControlledFrom()),
                minQty: ko.observable(item.minQty()),
                qtyIncrement: ko.observable(item.qtyIncrement()),
                getPrice: item.getPrice,
                suPrice: item.suPrice,
                shaKey: ko.observable(item.shaKey()),
                shipTo: ko.observable({}),
                moveItemToNewShipTo: self.moveItemToNewShipTo,
                removeItemToShipToMap: self.removeItemToShipToMap,
                availableAddresses: shippingAddresses,
                parentProductID: item.parentProductID
            });
            item.qty(item.qty() - (item.qtyIncrement() || 1));
            self.itemShipToMap.notifySubscribers();
        };

        self.currentPackage = ko.observable(function(){
            var item = new Object();
            item.shippingAddressId = ko.observable(sDefaultShaKey);
            item.shipTo = ko.observable()
            item.details = ko.observableArray([]);
            return item;
        }());


        self.toggleItemInCurrentPackage = function(item){
            if(!_.contains(self.currentPackage().details(),item)){
                self.currentPackage().details().push(item)
            }else{
                _.pull(self.currentPackage().details(), item)
            }
            self.currentPackage.notifySubscribers();
        };

        self.isInCurrentPackage = function(item){
            return _.contains(self.currentPackage().details(),item);
        };

        self.removeItemToShipToMap = function(item){
            _.pull(self.itemShipToMap(),item);
            self.itemShipToMap.notifySubscribers();
        };

        self.getTotalQty = function(instance){
            var totalQty = 0;
            var mappings = self.itemsOnOrder();
            if(self.useMultiShipEditUI && self.useMultiShipEditUI()){
                mappings = self.itemShipToMap();
            }
            _.each(mappings, function(map){
                if(map.instance() == instance  && map.qtyControlledFrom() != 1){
                    totalQty += parseFloat(map.qty());
                    //exit after the first item is found so the carrier product qty will display.
                    //or not - added && map.qtyControlledFrom() != 1 to account for config products
                    // qtyControlledFrom is "1" when controlled by the parent
                    //return false;
                }
            });
            return totalQty;
        };

        self.getOrderDetailQty = function(instance){
            var totalQty = 0;
            self.itemsOnOrder().forEach(function(map){
                if(map.instance() == instance && map.qtyControlledFrom() != 1){
                    totalQty += parseFloat(map.qty());
                }
            });
            return totalQty;
        };

        self.setItemShipToMapPrice = function(data){
            self.itemShipToMap().forEach(function(map){
                if(map.instance() == data.instance()){
                    if(self.superUserRestrictMinPrice() & data.superUserMinPrice() != null && data.price() < data.superUserMinPrice()) {
                        data.price(undefined);
                        data.price(data.superUserMinPrice());
                    }
                    map.suPrice = data.price();
                }
            });
        };

        self.setWorkerPriceOverride = function(data){
            var orderDetail = [];

            orderDetail.push({
                orderDetailKey: data.orderDetailKey(),
                PriceCalculationType: 'fixed',
                Price: data.price(),
                PriceBeforeAdjustment: data.price()
            });

            var postOptions = {
                data: "orderDetail=" + encodeURIComponent(JSON.stringify(orderDetail)),
                success: function(data) {
                    $('#cartAdvSettings.collapse').toggleClass('in'); 
                    $('#onOrderAdvBtn').toggleClass('active');
                },
                error: function() {
                    alert('Error saving Unit Price');
                }
            }

            postInfo(postOptions, 'setOrderDetailFields');
        }

        self.setWorkerQtyLimits = function(data) {
            var orderDetail = [];

            orderDetail.push({
                orderDetailKey: data.orderDetailKey(),
                MinQty: data.minQty(),
                MaxQty: data.maxQty(),
                QtyIncrement: data.qtyIncrement(),
                RemoveType: data.removeType()
            });

            var postOptions = {
                data: "orderDetail=" + encodeURIComponent(JSON.stringify(orderDetail)),
                success: function(data) {
                    $('#cartAdvSettings.collapse').toggleClass('in');
                    $('#onOrderAdvBtn').toggleClass('active');
                    toggleLoadingWidget(false);
                },
                error: function() {
                    alert('Error saving qty limits');
                }
            }
            toggleLoadingWidget(true);
            postInfo(postOptions, 'setOrderDetailFields');
        }

        self.resetSuperUserPriceOverride = function(data){
            var orderDetail = [];

           orderDetail.push({
                orderDetailKey: data.orderDetailKey(),
                PriceCalculationType: 'std'
            });

            var postOptions = {
                data: "orderDetail=" + encodeURIComponent(JSON.stringify(orderDetail)),
                success: function(data) {
                },
                error: function() {
                    alert('Error resetting Price Override');
                }
            }

            postInfo(postOptions, 'setOrderDetailFields');
        };

        self.resetSuperUserShippingPrice = function(data){
            var postOptions = {
                url: "payment.asp?o_key=" + viewModel.orderKey() + "&svc_key=" + data.shipViaChoiceKey() + '&ajax=true&pageaction=resetShippingPrice&randomnum=' + new Date().getTime() ,
                success: function(data) {
                },
                error: function() {
                    alert('error resetting shipping price');
                }
            }

            postInfo(postOptions, 'resetSuperUserShippingPrice');
        }

        self.returnToPendingOrders = function() {
            window.location = 'quotes.asp?revert=1';
        }

        self.superUserOrderFormMode = ko.observable(ofConfig.superUserOrderFormMode && ofConfig.isSuperUserSession);

        self.superUserSetShipViaPrice = function(data, event){
            var postOptions = {
                url: 'payment.asp' + '?o_key=' + viewModel.orderKey() + '&svc_key=' + data.shipViaChoiceKey() + '&price=' + event.target.value + '&ajax=true&pageaction=setShippingPrice&randomnum=' + new Date().getTime(),
                success: function(data) {
                },
                error: function() {
                    alert('error resetting shipping price');
                }
            };
            postInfo(postOptions, 'setShippingPrice');
        };

        self.postQtyUpdate = function() {

            var postUrl = 'i_i_add_to_cart.asp' + '?ajax=qtyUpdate&modal=1&o_key=' + viewModel.orderKey();
            var dataString = '';
            var unqString = '';
            var keyCount = 0;

            self.detailLines().forEach(function(detailLine) {
                if(dataString.length) dataString += '&';
                dataString += 'qty_' + detailLine.orderDetailKey() + '=' + detailLine.qty();
                if(unqString.length) unqString +=',';
                unqString += detailLine.orderDetailKey();
            });

            dataString += '&unqs=' + unqString;

            var postOptions = {
                url: postUrl,
                type: "POST",
                data: dataString,
                success: function(data) {
                    //
                },
                error: function() {
                    alert('error updating quantity');
                }
            }

            postInfo(postOptions, '','');
        }

        self.hasMultipleShipToAddresses = function() {
            var shaKeys = [];
            var hasMultipleAddresses = false;
            self.shipments().forEach(function(shipment) {
                var shaKey = shipment.shipTo().key();
                if(shaKeys.indexOf(shaKey)) {
                    shaKeys.push(shaKey);
                }
                if(shaKeys.length > 1) {
                    hasMultipleAddresses = true;
                    return;
                }
            });
            return hasMultipleAddresses;
        };

        self.useMultiShipEditUI = ko.observable(self.hasMultipleShipToAddresses());

        self.allocateShipments = function(moveToNextStep){
            var shipmentArray = [];
            var listOfShaKeys = [];
            var newShipmentKey;
            var orderDetail = [];

            toggleLoadingWidget(true);

            if(viewModel.useMultiShipEditUI()){

                //Get a unique list of shipping address keys
                self.itemShipToMap().forEach(function(item){
                    if ( listOfShaKeys.indexOf( item.shipTo().key() ) == -1 ){
                        listOfShaKeys.push(item.shipTo().key());
                    }
                })

                //Loop the sha_keys to create shipments for each
                var items = self.itemShipToMap();
                var newShipmentCount = 0;
                listOfShaKeys.forEach(function(shaKey){
                    //reuse existing shipment keys if they exist.
                    if( newShipmentCount+1 <= self.shipments().length ){
                        newShipmentKey = self.shipments()[newShipmentCount].key();
                    }else{
                        newShipmentKey = utils.createGuid();
                    }

                    var shipmentInfo = {
                        Key: newShipmentKey,
                        ShipmentId: newShipmentKey,
                        ShippingAddressId: shaKey,
                        Details: []
                    };

                    //Loop the product - ship to mapping records to create shipment details
                    var shipments = items;
                    shipments.forEach(function(shipment){
                        if(shipment.shipTo().key() == shaKey){
                            shipmentInfo.Details.push( {
                                OrderDetailId: shipment.orderDetailKey,
                                QtyToShip: shipment.qty()
                            })
                        }
                    });
                    newShipmentCount++;
                    shipmentArray.push(shipmentInfo);
                });
            }else{
                listOfShaKeys.push(self.shipments()[0].shipTo().key());

                //Single Shipping - reuse the first shipment key
                newShipmentKey = self.shipments()[0].key();
                var shipmentInfo = {
                    Key: newShipmentKey,
                    ShipmentId: newShipmentKey,
                    ShippingAddressId: self.shipments()[0].shipTo().key(),
                    Details: []
                };

                //JB - loop the items on order since we're in single shipment mode.
                viewModel.itemsOnOrder().forEach(function(item){
                    shipmentInfo.Details.push( {
                        OrderDetailId:  item.orderDetailKey(),
                        QtyToShip: item.qty()
                    });
                });
                shipmentArray.push(shipmentInfo);
            }

            //Remove any orphaned shipments from the original data if the user is created shipments
            if(listOfShaKeys.length < self.shipments().length && oConfig.allowUserCreatedShipments){
                var count = 0;
                _.eachRight(self.shipments(), function(oldShipment){
                    if( count + 1 <= (self.shipments().length - listOfShaKeys.length ) ){
                        shipmentArray.push({
                            Key: oldShipment.key(),
                            Delete: true
                        });
                        count++;
                    }
                });
            }

            //Order Detail Field Updates
            var details = self.itemShipToMap()
            _.each(details, function(item){
                var superUserPrice = parseFloat(item.suPrice);
                var getprice = parseFloat(item.getPrice());

                if( isNaN(superUserPrice)){
                    superUserPrice = getprice;
                }

                if(viewModel.superUserOrderFormMode()) {
                    if (getprice != superUserPrice) {
                        //build OD object
                        if(!_.find(orderDetail, {orderDetailKey: item.orderDetailKey}) ){
                            var obj = {
                                orderDetailKey: item.orderDetailKey,
                                Price: superUserPrice,
                                PriceDisplay: getprice,
                                PriceCalculationType: 'fixed'
                            };

                            if(ofConfig.useTradeAdjustmentOnSession){
                                obj.PriceBeforeAdjustment = superUserPrice;
                            }
                            orderDetail.push(obj);
                        }
                    }

                    var detail = _.find(orderDetail, {orderDetailKey: item.orderDetailKey});

                    if(!detail) {
                        detail = {
                            orderDetailKey: item.orderDetailKey
                        }
                        orderDetail.push(detail);
                    }

                    // var newValues = _.find(viewModel.itemsOnOrder(), {orderDetailKey: item.orderDetailKey});

                    var itemOnOrder = viewModel.itemsOnOrder().reduce(function(returnItem, currentItem) {
                        if(currentItem.orderDetailKey() == item.orderDetailKey) {
                            returnItem = currentItem;
                        }
                        return returnItem;
                    })

                    detail.MinQty       = parseFloat(itemOnOrder.minQty ? itemOnOrder.minQty() : 0);
                    detail.MaxQty       = parseFloat(itemOnOrder.maxQty ? itemOnOrder.maxQty() : 0);
                    detail.QtyIncrement = parseFloat(itemOnOrder.qtyIncrement ? itemOnOrder.qtyIncrement() : 1);

                    // TODO: Need to track original removeType value - checking has children for now
                    var defaultRemoveType = itemOnOrder.hasChildProducts() ? 'instance' : 'OD_Key';

                    detail.RemoveType   = itemOnOrder.removeType ? itemOnOrder.removeType() : defaultRemoveType;

                    runHook('allocateShipmentsOrderDetailUpdate', { itemOnOrder: itemOnOrder, detailLine: detail });
                }
                toggleLoadingWidget(false);
            });

            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)) + "&orderDetail=" + encodeURIComponent(JSON.stringify(orderDetail)),
                success: function(){
                    if(ofConfig.bUsePromotions){
                        jQuery.ajax({
                            url: 'payment.asp' + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=checkPromos&randomnum=' + new Date().getTime()
                            , cache: false
                            , type: 'GET'
                            , success: function(data,status,request){
                                if(JSON.parse(data)){
                                    viewModel.processing(true);

                                    //redirect to reward selection page.
                                    //This is not opening in a modal for responsive reasons.
                                    var nextPage = encodeURIComponent('payment.asp?o_key=' + viewModel.orderKey() + (ofConfig.isModal ? '&modal=1' : ''));
                                    document.location = 'promo_reward_selection.asp?quickadd=1&next_page=' + nextPage + '&o_key=' + viewModel.orderKey() + (ofConfig.isModal ? '&modal=1' : '');
                                }
                            }
                            , error: function(data) {
                                console.log('Error checking Promos');
                            }
                            , complete: function(data) {
                            }
                        });
                    }
                },
                error: function() {
                    self.addShipment();
                    autoAllocateItems();
                    alert('error saving product list on shipment');
                }
            }

            postInfo(postOptions, 'updateShipToAddress');
            if(moveToNextStep === undefined) {
                moveToNextStep=true;
            }
            if(self.isOverLineLimit()){
                moveToNextStep = true;
            }
            console.log(self);
            self.shippingComplete(moveToNextStep);
            self.shippingComplete.notifySubscribers();
            if(moveToNextStep) {
                utils.setCookie(self.orderKey() + '-step' , '3');
            }
        };


        self.showShippingEdit = ko.observable(!self.completed());
        self.currentShipment = ko.observable();

        self.toggleMultiShip = function (data, event) {
            event.preventDefault();
            self.useMultiShipEditUI(!self.useMultiShipEditUI());

            self.shippingComplete.notifySubscribers();
        };

        self.toggleOrderPlaced = function (data, event) {
            event.preventDefault();

            var postData = {};

            if(viewModel.paymentMethod.paymentType() === 'cc') {

                var defaultCcnChecked = $('#ccpm_default_ccn_id_selection').is(':checked');

                if(defaultCcnChecked) {
                    postData.setDefaultCcn = 1
                }

                postData.ccn_key =  $('#ccpm_ccn_id').val();
                postData.address =  $('#ccpm_address_input').val();
                postData.city =     $('#ccpm_city_input').val();
                postData.country =  $('#ccpm_country_input').val();
                postData.state =    $('#ccpm_state_dropdown').prop('disabled') ? $('#ccpm_state_text').val() : $('#ccpm_state_dropdown').val();
                postData.zip =      $('#ccpm_zip_input').val();

                //oSavedPaymentMethodsCreditCard.saveBillingAddress();
            }

            var postOptions = {
                data: postData,
                success: function(data){
                    viewModel.updateOrderAccess();
                    var response = JSON.parse(data);
                    if(Object.keys(response[0].Errors).length == 0) {
                        //document.location = 'payment.asp?o_key=' + viewModel.orderKey() + '#checkout_confirmation';
                        scrollToSection('#checkout');
                    }else{
                        scrollToSection('#checkout');
                    }
                },
                error: function(data) {
                    alert('error placing order');
                }
            }


            if ($.active > 0) {
                viewModel.processing(true);
                $( document ).one("ajaxStop", function(){
                    postInfo(postOptions, 'placeOrder');
                });
            }
            else {
                postInfo(postOptions, 'placeOrder');
            }

        };

        self.showItemSelector = function(shipment) {
            shipment.detailsMap([]);
            self.detailLines().forEach(function(detailLine, detailIndex, detailArray) {
                shipment.detailsMap().push(new detailMap(detailLine, shipment, self));
            });

            self.currentShipment(shipment);
            $('#modal_add_prods').modal('show');
        };

        self.addShipment = function() {

            var newShipment = getNewShipment();

            var successFunction;

            if(self.shipments().length === 0) {
                /* EJ - 2016-11-15
                   I feel dirty about this, but it's a quick workaround for an odd issue
                   happening on first load of the payment page for a new order, before the first
                   shipment is added.  The issue presents as a "corrupt" countries array (missing
                   states for first country) and validation issues on Account form.

                   The only difference in code on client (verified with Arraxis Merge) is the orderPayload.
                   The first page load doesn't have shipments or paymethods (empty array and null respectively),
                   whereas the second and all subsequent page loads do.

                   The issue goes away once the first shipment is added, so I'm forcing a reload
                   the first time a shipment is added, which was already happening already
                   on first page load if there were no shipments on the order.

                   The first shipment being added needs to be moved to the ordering object eventually,
                   which will negate the need for this code anyway, so I didn't spend more hours trying
                   to find the root cause.
                */

                // so spinner stays active until location.reload happens
                self.activeAjaxRequestCount(self.activeAjaxRequestCount() + 1);

                successFunction = function() {
                    location.reload();
                }
            } else {
                successFunction = autoAllocateItems;
            }


            var shipmentArray = [];

            var shipmentInfo = {
                Key: newShipment.key(),
                ShipmentId: newShipment.key(),
                Details: []
            };

            shipmentArray.push(shipmentInfo);


            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)),
                error: function() {
                    alert('error setting Shipping Method');
                },
                success: successFunction
            }

            postInfo(postOptions, 'updateShipToAddress', newShipment.key(), self);

        };

        self.deleteShipment = function(shipmentToDelete, e, index) {

            var shipmentArray = [];

            var shipmentInfo = {
                Key: shipmentToDelete.key(),
                Delete: true
            };

            shipmentArray.push(shipmentInfo);

            var postOptions = {
                data: "shipmentJson=" + encodeURIComponent(JSON.stringify(shipmentArray)),
                error: function() {
                    alert('error moving all items to shipment');
                },
                success: autoAllocateItems
            }

            postInfo(postOptions, 'updateShipToAddress', 'checkout_shipping');
        };
        self.setShipTo = function(shipment, shipToAddress) {

            var sha_id = shipToAddress.key();
            var shipmentId = shipment.key();

            var postOptions = {
                data: "shipmentId=" + shipmentId + "&sha_id=" + sha_id,
                success: function(data) {
                    autoAllocateItems();
                    self.shipmentsSectionsValid.notifySubscribers();
                },
                error: function() {
                    alert('error saving shipping address');
                }
            }

            postInfo(postOptions, 'setSha');

            $('#modal_addressbook[tabindex="-1"]:hidden').remove()
            $('#modal_addressbook').modal('hide');
        };

        self.showNewAddressForm = function(shipment) {
            shipment.shipTo(new addressInfo(getNewAddress()));

            $('#modal_addressbook[tabindex="-1"]:hidden').remove()
            $('#modal_addressbook').modal('hide');
        };

        self.showAddAddress = function(shipment){

            $('#modal_add_shipto').modal('show');
        };

        self.shipments().forEach(function(shipment) {

            self.detailLines().forEach(function(detailLine, detailIndex, detailArray) {
                shipment.detailsMap().push(new detailMap(detailLine, shipment, self));
            });
        });

        self.updatePoRequired = function() {
            if(self.paymentMethod && self.paymentMethod.paymentMethodKey() != ''){
            var isReallyRequired = self.paymentMethod.poRequired() && self.paymentMethod.collectPO();
            self.paymentMethod.poRequired(isReallyRequired);
        }
        }

        self.updatePoRequired();

        self.poNumber.extend({
            required: {
                onlyIf: function() {
                    return viewModel && viewModel.paymentMethod.poRequired()
                }
            }
        });

        self.poNumber.subscribe(function(poNumber) {
            postOrderHeaderField("ponumber", poNumber);
        });

        self.comments.subscribe(function(newComments) {
            postOrderHeaderField("comment", newComments);
        });

        self.nickname.subscribe(function(nickname) {
            postOrderHeaderField("nickname", nickname);
        });

        self.isValidDate = function(date){
            //Quick fix to hide invalid expiration.
            //ToDo: update to check for other "invalid" dates.

            // Parse the date parts to integers
            var parts = date.split("-");
            var day = parseInt(parts[2], 10);
            var month = parseInt(parts[1], 10);
            var year = parseInt(parts[0], 10);

            // Check the ranges of month and year
            if(year < 1000 || year > 3000 || month == 0 || month > 12)
                return false;

            var monthLength = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

            // Adjust for leap years
            if(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
                monthLength[1] = 29;

            // Check the range of the day
            return day > 0 && day <= monthLength[month - 1];
        };

        self.getMinimumRecurringOrderDate = function(){
            var today = moment();
            var minimumDate = moment(today).add(1, 'days');
            return moment(minimumDate).format("MM/DD/YYYY");
        }

        self.roRunDate.subscribe(function(roRunDate) {
            postOrderHeaderField("ro_rundate", roRunDate);
        });

        self.roRecCase.subscribe(function(roRecCase) {
            postOrderHeaderField("ro_rec_case", roRecCase);
        });

        self.roRecQty.subscribe(function(roRecQty) {
            postOrderHeaderField("ro_rec_qty", roRecQty);
        });

        self.updateRecurringType = function(data, event){
            newValue = event.target.value;
            sOrderDetailKey = data.orderDetailKey();
            switch(newValue){
                case 'fixed':
                    postOrderDetailFields(sOrderDetailKey, ['ro_recurring_type','ro_skip_next_runs'], ['fixed',0]);
                    break;
                case 'recurring':
                    postOrderDetailFields(sOrderDetailKey, ['ro_recurring_type','ro_skip_next_runs'], ['recurring',0]);
                    break;
                case 'skipnext':
                    postOrderDetailFields(sOrderDetailKey, ['ro_recurring_type','ro_skip_next_runs'], ['recurring',1]);
                    break;
                case 'remove':
                    viewModel.removeProduct(data);
                    break;
            }

        };

        self.getRecurringLabel = function(data){
            var sMessage = '';
            var sAction = data.orderDetail.roRecurringType();
            var sSkipRuns = data.orderDetail.roSkipNextRuns();
            switch(sAction){
                case 'recurring':
                case '':
                    if(sSkipRuns == 0){
                        //recurring
                        sMessage = ofConfig.roRecurringItemLabel;
                    }else{
                        //skip.
                        sMessage = ofConfig.roSkippedItemLabel;
                    }
                    break;
                case 'fixed':
                        sMessage = ofConfig.roOnetimeItemLabel;
                    break;
                case 'disabled':
                        sMessage = ofConfig.roDisabledItemLabel;
                    break;
            }
            return sMessage;
        };
        self.customerComment = ko.observable('');

        self.noteBook = ko.observable();

        self.populateNoteBook = function(){
            var noteBook = {};
            var count = 0;

            noteBook.notes =  ko.observableArray([]);

            if(noteBookPayload.length > 0 ){

                noteBook.nbKey = noteBookPayload[0].nb_key;
                noteBook.id    = noteBookPayload[0].id;
                noteBook.refId = noteBookPayload[0].ref_id;

                _.each(noteBookPayload,function(note){
                    if(note.internal_notes || note.external_notes) {
                        count++;
                        item = {};

                        item.internalNotes    = note.internal_notes;
                        item.externalNotes    = note.external_notes;
                        item.postedByName     = note.c_f_nm + ' ' + note.c_l_nm;
                        item.postedByUsername = note.username;
                        item.createDate       = note.create_date;
                        noteBook.notes.push(ko.observable(item));
                    }
                });
            }

            self.noteBook(noteBook);
        }();

        self.buildOrderHeaderFields = function(aFields) {
            //Available order header fields that can be POSTed using this function
            var orderHeaderFields = {
                "UseMultipleShipments": viewModel.useMultipleShipments(),
                "Nickname" : viewModel.nickname(),
                "QuoteExpirationDate": viewModel.expirationDate()
            };

            var orderHeaderFieldsJson = {};

            //Add only the field(s) that are passed in aFields.
            _.forEach(aFields, function(sField) {
                orderHeaderFieldsJson[sField] = orderHeaderFields[sField];
            });

            self.setOrderHeaderFields(orderHeaderFieldsJson);

        };

        self.setOrderHeaderFields = function(orderHeaderFieldsJson) {

            var postOptions = {
                data: "orderHeaderFields=" + encodeURIComponent(JSON.stringify(orderHeaderFieldsJson)),
                error: function(data) {
                    alert('error setting Order Header fields');
                }
            };

            postInfo(postOptions, 'setOrderHeaderFields');
        };

        if(self.shipments().length === 0) {
            //self.addShipment();
        }

        self.setPaymentMethod = function(paymentMethod) {
            if(paymentMethod.paymentType() != viewModel.paymentMethod.paymentType()){
                var postOptions = {
                    data: "pm_id=" + paymentMethod.paymentMethodKey(),
                    error: function(data) {
                        alert('error setting pm');
                    },
                    success: function() {
                        $('#ccpm_container').removeClass('hide');
                        viewModel.updatePoRequired();
                    }
                }

                postInfo(postOptions, 'setPmId');
            }
        }

        self.ccn_id.subscribe(function(newCCN) {
            if(newCCN !== '') {
                var payload = 'ccn_id=' + newCCN;
                var postOptions = {
                    data: payload,
                    error: function(data) {
                        alert('error setting CCN');
                    }
                }

                postInfo(postOptions, 'setCCN');
            }
        });

        self.SetCouponCode = function(couponCode) {
            var payload = 'couponcode=' + encodeURIComponent(couponCode);
            var postOptions = {
                data: payload,
                error: function(data) {
                    alert('error applying coupon');
                }
            }

            postInfo(postOptions, 'setCoupon');
        }

        self.SetGiftCertificate = function(giftCertCode) {
            var payload = 'giftCertCode=' + encodeURIComponent(giftCertCode);
            var postOptions = {
                data: payload,
                error: function(data) {
                    alert('error applying gift certificate');
                }
            }

            postInfo(postOptions, 'setGiftCertCode');
        };

        self.allItemsAllocated = ko.computed(function() {
            var totalItemCount = self.detailLines().reduce(function(previous, current) {
                return previous + current.qty();
            }, 0);

            var allocatedItemCount = 0;
            self.shipments().forEach(function(shipment) {
                allocatedItemCount += shipment.details().reduce(function(previous, current) {
                    return previous + current.qtyToShip();
                }, 0);
            });

            return totalItemCount === allocatedItemCount;
        });

        self.itemsOnOrder = ko.computed(function() {
            var items = [];
            self.detailLines().forEach(function(detailLine) {
                detailLine.hasChildProducts = ko.observable(function() {
                    return self.detailLines().filter(function(outerLine) {
                        return outerLine.instance() == detailLine.instance()
                                && detailLine.removeType() != 'instance'
                    }).length > 1
                }());

                detailLine.hasParentInCart = ko.observable(function() {
                    return self.detailLines().filter(function(outerLine) {
                        return outerLine.orderDetailKey() != detailLine.orderDetailKey()
                                && outerLine.instance() == detailLine.instance()
                                && detailLine.removeType() == 'instance'
                    }).length > 0
                }());

                detailLine.instanceChildren = self.detailLines().filter(function(item) {
                    return item.instance() == detailLine.instance() && item.removeType() != 'instance' && item.parentProductID().trim() != '' && item != detailLine;
                }) || [];

                var mainProduct = self.detailLines().filter(function(item) {
                                                return item.instance() == detailLine.instance() && item.removeType() == 'instance';
                                            })[0] || detailLine;

                var mainProductQty = mainProduct.qty();

                detailLine.superUserMinPrice = ko.observable(detailLine.commodity[ofConfig.superUserMinPriceProperty]() || 0);

                detailLine.instanceUnitPrice = ko.observable(self.detailLines().reduce(function(current, item) {
                    if(item.instance() == detailLine.instance()) {
                        if(item.parentProductID().trim() != '' && item.removeType() != 'instance') {
                            return current += item.extTotal() / mainProductQty;
                        } else {
                            return current += item.price();
                        }
                    } else {
                        return current;
                    }
                },0));

                detailLine.instanceUnitPriceDisplay = ko.computed(function(){
                    return utils.formatMoney(detailLine.instanceUnitPrice());
                });

                detailLine.instanceExtPrice = ko.observable(self.detailLines().reduce(function(current, item) {
                    if(item.instance() == detailLine.instance()) {
                        return current += item.extTotal();
                    } else {
                        return current;
                    }
                },0));

                detailLine.allocatedQty = ko.observable(function() {
                    var runningTotal = 0;
                    self.shipments().forEach(function(shipment) {
                        shipment.details().forEach(function(shipDetail) {
                            if(shipDetail.orderDetailId() === detailLine.orderDetailKey()) {
                                runningTotal += shipDetail.qtyToShip();
                            }
                        });
                    });
                    return runningTotal;
                }());

                detailLine.minGrossMarginPercent = ko.computed(function() {
                    if(self.superUserRestrictMinPrice() & detailLine.superUserMinPrice() != null)
                    {
                        return ( (detailLine.superUserMinPrice() - detailLine.commodity.cost()) / detailLine.superUserMinPrice() * 100 ).toFixed();
                    } else {
                        return undefined;
                    }
                });

                detailLine.grossMarginPercent = ko.computed({
                    write: function(newVal) {
                        var localGrossMarginPercent = parseInt(detailLine.minGrossMarginPercent() || 0);
                        var val = parseInt(newVal);
                        if(val < localGrossMarginPercent) {
                            val = localGrossMarginPercent;
                        }
                        var marginPercent = val / 100;
                        var markup = marginPercent / (1 - marginPercent);
                        var newPrice = (detailLine.commodity.cost() * (1 + markup)).toFixed(2);
                        detailLine.price(undefined);
                        detailLine.price(newPrice);
                        detailLine.priceCalculationType('fixed');
                    },
                    read: function() {
                        var marginPercent = (detailLine.price() - detailLine.commodity.cost()) / detailLine.price();
                        return (marginPercent * 100).toFixed(0);
                    },
                    deferEvaluation: true
                });

                detailLine.minMarkupPercent = ko.computed(function() {
                    if(self.superUserRestrictMinPrice() & detailLine.superUserMinPrice() != null)
                    {
                        return ( detailLine.superUserMinPrice() / detailLine.commodity.cost() - 1 ).toFixed();
                    } else {
                        return undefined;
                    }
                });

                detailLine.markupPercent = ko.computed({
                    write: function(newVal) {
                        var minMarkupPercent = parseInt(detailLine.minMarkupPercent || 0);
                        var val = parseInt(newVal);
                        if(val < minMarkupPercent) {
                            val = minMarkupPercent;
                        }
                        var markup = val / 100;
                        var newPrice = (detailLine.commodity.cost() * (1 + markup)).toFixed(2);
                        detailLine.price(undefined);
                        detailLine.price(newPrice);
                        detailLine.priceCalculationType('fixed');
                    },
                    read: function() {
                        var markup = (detailLine.price() - detailLine.commodity.cost()) / detailLine.commodity.cost();
                        return (markup * 100).toFixed(0);
                    },
                    deferEvaluation: true
                });

                detailLine.maxDiscountPercent = ko.computed(function() {
                    if(self.superUserRestrictMinPrice() & detailLine.superUserMinPrice() != null)
                    {
                        return (100 * (1 - (detailLine.superUserMinPrice() / detailLine.commodity.retailPrice()))).toFixed();
                    } else {
                        return undefined;
                    }
                });

                detailLine.discountPercent = ko.computed({
                    write: function(newVal) {
                        var maxDiscountPercent = parseInt(detailLine.maxDiscountPercent() || 100);
                        var val = parseInt(newVal);
                        if(val > maxDiscountPercent) {
                            val = maxDiscountPercent;
                        }
                        var discount = val / 100;
                        var newPrice = (detailLine.commodity.retailPrice() * (1 - discount)).toFixed(2);
                        detailLine.price(undefined);
                        detailLine.price(newPrice);
                        detailLine.priceCalculationType('fixed');
                    },
                    read: function() {
                        var discount = 1 - detailLine.price() / detailLine.commodity.retailPrice();
                        return (discount * 100).toFixed(0);
                    },
                    deferEvaluation: true
                });

                detailLine.minGrossMarginAmount = ko.computed(function() {
                    if(self.superUserRestrictMinPrice() & detailLine.superUserMinPrice() != null)
                    {
                        return detailLine.superUserMinPrice() - detailLine.commodity.cost();
                    } else {
                        return undefined;
                    }
                });

                detailLine.grossMarginAmount = ko.computed({
                    write: function(newVal) {
                        var localMminGrossMarginAmount = parseInt(detailLine.minGrossMarginAmount() || 0);
                        var val = parseInt(newVal);
                        if(val < localMminGrossMarginAmount) {
                            val = localMminGrossMarginAmount;
                        }
                        var grossMargin = parseFloat(val);
                        var newPrice = (detailLine.commodity.cost() + grossMargin).toFixed(2);
                        detailLine.price(undefined);
                        detailLine.price(newPrice);
                        detailLine.priceCalculationType('fixed');
                    },
                    read: function() {
                        return (detailLine.price() - detailLine.commodity.cost()).toFixed(2);
                    },
                    deferEvaluation: true
                });

                detailLine.allowDeletes = ko.computed({
                    write: function(val) {
                        // TODO: need to store previous value for removeType (od_key, hide, instance) - checking child prods for now
                        if(val) {
                            detailLine.hasChildProducts() ? detailLine.removeType('instance') : detailLine.removeType('OD_Key');
                        } else {
                            detailLine.removeType('hide');
                        }
                    },
                    read: function() {
                        return !(detailLine.removeType() == 'hide')
                    }
                });

                detailLine.suMinQty = ko.computed({
                    write: function(val) {
                        val = parseFloat(val);
                        if(isNaN(val)) {
                            val = detailLine.minQty();
                        }
                        if(!detailLine.maxQty() == 0 && val > detailLine.maxQty()) {
                            detailLine.minQty(detailLine.maxQty());
                        } else {
                            detailLine.minQty(val);
                        }
                        detailLine.suMaxQty(detailLine.maxQty());
                        detailLine.suMinQty.notifySubscribers();
                    },
                    read: function() {
                        return detailLine.minQty();
                    }
                });

                detailLine.suMaxQty = ko.computed({
                    write: function(val) {
                        var originalValue = detailLine.maxQty();
                        var newValue = parseFloat(val);;

                        if(isNaN(newValue)) {
                            newValue = originalValue;
                        }
                        if(newValue > 0) {
                            if(detailLine.minQty() > 0 && newValue < detailLine.minQty()) {
                                newValue = detailLine.minQty();
                            } else {
                                var diff = (newValue-detailLine.minQty()) % detailLine.qtyIncrement();
                                newValue = newValue - diff;
                                newValue = detailLine.minQty() > 0 && newValue < detailLine.minQty() ? detailLine.minQty() : newValue;
                            }
                        } else {
                            newValue = 0;
                        }

                        // reset maxQty to workaround KO bug that causes
                        // underlying value to be changed, but the UI to
                        // not update if the end value is the same as the
                        // original value
                        /* - not a bug, need to notifySubscribers UI was broken
                        detailLine.maxQty(99);
                        detailLine.maxQty(0);
                        */

                        // set valid newValue
                        detailLine.maxQty(newValue);
                    },
                    read: function() {
                        return detailLine.maxQty();
                    }
                });

                detailLine.suQtyIncrement = ko.computed({
                    write: function(val) {
                        val = parseFloat(val);
                        if(isNaN(val)) {
                            val = detailLine.qtyIncrement();
                        }
                        detailLine.qtyIncrement(val);
                        detailLine.suMaxQty(detailLine.maxQty());
                        detailLine.suQtyIncrement.notifySubscribers();
                    },
                    read: function() {
                        return detailLine.qtyIncrement();
                    }
                });

                detailLine.selectedRoAction = ko.computed(function(){
                    var sAction = detailLine.roRecurringType();
                    var skipNextRuns = detailLine.roSkipNextRuns();
                    if( sAction == '' || sAction == 'recurring'){
                        if( skipNextRuns == 0){
                            sAction = 'recurring';
                        }else{
                            sAction = 'skipnext';
                        }
                    }
                    return sAction;
                });

                items.push(detailLine);
            });

            runHook('ItemsOnOrderArrayBeforeReturn', { detailLines: items });

            return items;
        });
        
        self.detailLines.subscribe(function(){
            self.isMinimumOrderTotalMet(checkOrderTotal(self));
        });
        self.itemsOnOrder.subscribe(function(){
            self.isMinimumOrderTotalMet(checkOrderTotal(self));
        });

        self.itemShipToMap = ko.computed(function(){
            var items = [];
            self.shipments().forEach(function(shipment) {
                oShipTo = shipment.shipTo();

                shipment.details().forEach(function(shipDetail) {
                    var item                   = new Object();
                    item.shaKey                = ko.observable(oShipTo.key());
                    item.key                   = ko.observable(shipDetail.orderDetailId());
                    item.orderDetailKey        = shipDetail.orderDetailId();
                    item.instance              = ko.observable(shipDetail.orderDetail.instance());
                    item.qty                   = ko.observable(shipDetail.qtyToShip());
                    item.qtyControlledFrom     = ko.observable(shipDetail.orderDetail.qtyControlledFrom());
                    item.qtyIncrement          = ko.observable(shipDetail.orderDetail.qtyIncrement());
                    item.getPrice              = shipDetail.orderDetail.price,
                    item.suPrice               = shipDetail.orderDetail.price,
                    item.minQty                = ko.observable(shipDetail.orderDetail.minQty());
                    item.moveItemToNewShipTo   = self.moveItemToNewShipTo;
                    item.removeItemToShipToMap = self.removeItemToShipToMap;
                    item.availableAddresses    = shippingAddresses;
                    item.shipTo                = ko.observable({});
                    item.parentProductID       = shipDetail.orderDetail.parentProductID();
                    item.availableAddresses().forEach(function(address,index){
                        if( address.key() == oShipTo.key()){
                            item.shipTo(address);
                        }
                    });

                    if(shipDetail.orderDetail.instanceChildren.length > 0){
                        item.shipTo.subscribe(function(newValue) {
                            items.forEach(function(map) {
                                if(map.instance() == item.instance() && map.shipTo().key() != item.shipTo().key()) {
                                    map.shipTo(item.shipTo());
                                }
                            })
                        });
                    }

                    items.push(item);
                })
            });

            return items;
        });
        
        _.each(self.itemShipToMap(), function(item){
            item.qty.subscribe(function () { 
                self.isMinimumOrderTotalMet(checkOrderTotal(self));
            });   
        });

        self.selectedOrderActionRefId = ko.observable(
            function(){
                if(self.orderActions().length > 0 ){
                    return self.orderActions()[0].refID();
                }else{
                    return '';
                }
            }()
        );

        self.selectedOrderAction = ko.computed(
            function(){
                var action = _.find(self.orderActions(), function(action){
                    if( action.refID() == self.selectedOrderActionRefId() ){
                        return action;
                    }
                });
                if(action && action.refID()){
                    return action;
                }else if(self.orderActions().length > 0 ){
                    return self.orderActions()[0];
                }else{
                    return {
                        showPaymentMethods: ko.observable(true),
                        showRecurringOrderSettings: ko.observable(false)
                    };
                }
            }
        );

        self.showOrderActionButton = function(data, parent) {
            //override this function for custom logic to show custom buttons
            var sSelectedRefId = self.selectedOrderAction() && self.selectedOrderActionRefId();
            var bShow = data.showButton() && (data.refID() == sSelectedRefId || parent.orderActions().length == 1);

            return bShow;
        };

        self.getAddressFinderId = function(id, data, parent){
            selector = id + '_' + parent.orderDetailKey + '_' + ($.isEmptyObject(data) ? 0 : data.key());
            return selector;
        };

       self.selectedLifecycleStage = ko.computed(function(){
            var stage = _.find(self.lifecycleStages(), function(stage){
                if( stage.refID() == self.lifecycleStage() ){
                    return stage;
                }
            });
            if(stage){
                return stage;
            }else{
                return {
                    alwaysShowMessage: ko.observable(false),
                    confirmationMessage: ko.observable('')
                };
            }
       });

        if(self.lifecycleStage() == 'cancelled'){
            self.completed(true);
        }

        self.showConfirmationMessage = ko.observable(function(){
            return (self.completed() || self.lifecycleStage() == 'pending' || self.lifecycleStage() == 'cancelled' || self.selectedLifecycleStage().alwaysShowMessage());
        }())

        self.allowAccountEdits         = ko.observable(self.allowAccountEdits() && ofConfig.AllowAccountEdits);
        self.allowShaEdits             = ko.observable(self.allowShaEdits() && ofConfig.AllowShippingEdits);
        self.allowWarehouseSelection   = ko.observable(ofConfig.allowWarehouseSelection );
        self.superUserRestrictMinPrice = ko.observable(ofConfig.superUserRestrictMinPrice);

        self.postOrderToGoogleAnalytics  = function() {
            if (self.completed() && self.tracked() != '1' ) {
                if(ofConfig.t_gtm) {
                    try {
                        var productsOrdered = [];
                        var transactionProducts = [];

                        for(var i = 0; i < self.detailLines().length; i++) {
                            var line = self.detailLines()[i];

                            productsOrdered.push({
                                'orderNumber': self.orderNumber(),
                                'name': self.customer.firstName() + ' ' + self.customer.lastName(),
                                'sku': line.sku(),
                                'category': line.searchfield1(),
                                'brand': line.searchfield5(),
                                'unitPrice': line.price(),
                                'quantityOrdered': line.qty()
                            });

                            // id is used for Enhanced Ecommerce
                            // sku is used for Google Analytics (non-EE)
                            transactionProducts.push({
                                'id': line.sku(),
                                'sku': line.sku(),
                                'name': line.name(),
                                'category': line.searchfield1(),
                                'price': line.price(),
                                'quantity': line.qty()
                            });
                        }

                        window.dataLayer.push({ 'pageType' : 'confirmation' });
                        window.dataLayer.push({ 'orderNumber' : self.orderNumber() });
                        window.dataLayer.push({ 'storeName' : ofConfig.t_tracking_company });
                        window.dataLayer.push({ 'productTotal' : self.productTotal() });
                        window.dataLayer.push({ 'shippingTotal' : self.shippingTotal() });
                        window.dataLayer.push({ 'taxTotal' : self.taxTotal() });
                        window.dataLayer.push({ 'orderTotal' : self.orderTotal() });
                        window.dataLayer.push({ 'customerName' : self.customer.firstName() + ' ' + self.customer.lastName() });
                        window.dataLayer.push({ 'customerFirstname' : self.customer.firstName() });
                        window.dataLayer.push({ 'customerLastName' : self.customer.lastName() });
                        window.dataLayer.push({ 'customerCity' : self.account.city() });
                        window.dataLayer.push({ 'customerState' : self.account.state() });
                        window.dataLayer.push({ 'customerCountry' : self.account.country() });
                        window.dataLayer.push({ 'customerEmail' : self.customer.email() });
                        window.dataLayer.push({ 'couponCode' : self.couponCode() });
                        window.dataLayer.push({ 'couponAmount' : self.couponDiscountTotals.totalDiscount() });
                        window.dataLayer.push({ 'paymentMethod' : self.paymentMethod.name() });
                        window.dataLayer.push({ 'sessionIP' : ofConfig.SessionIP });

                        // For Google Analytics (non-EE)
                        window.dataLayer.push({
                            'transactionId': self.orderNumber(),
                            'transactionAffiliation': ofConfig.t_tracking_company,
                            'transactionTotal': self.orderTotal(),
                            'transactionTax': self.taxTotal(),
                            'transactionShipping': self.shippingTotal(),
                            'transactionProducts': transactionProducts
                        });

                        // For Enhanced Ecommerce
                        window.dataLayer.push({
                            'event': ofConfig.t_gtm_transaction_event_name,
                            'ecommerce': {
                                'purchase': {
                                    'actionField': {
                                        'id': self.orderNumber(),
                                        'affiliation': ofConfig.t_tracking_company,
                                        'revenue': self.orderTotal(),
                                        'tax': self.taxTotal(),
                                        'shipping': self.shippingTotal(),
                                        'coupon': self.couponCode()
                                    },
                                    'products': transactionProducts
                                }
                            }
                        });

                        window.dataLayer.push({ 'productsOrdered' : productsOrdered });

                    } catch(err) {}

                }

                switch(ofConfig.t_analytics) {
                    case 'ga':
                        // do old analytics

                        try {

                            // add transaction details
                            var _gaq = _gaq || [];
                            _gaq.push(['_addTrans',
                                self.orderNumber(),      // Order ID
                                self.customer.firstName() + ' ' + self.customer.lastName(),  // Customer
                                self.orderTotal(),       // Total
                                self.taxTotal(),         // Tax
                                self.shippingTotal(),    // Shipping
                                self.account.city(),     // City
                                self.account.state(),    // State
                                self.account.country()   // Country
                            ]);

                            for(var i = 0; i < self.detailLines().length; i++) {
                                var line = self.detailLines()[i];

                                // add order item details
                                _gaq.push(['_addItem',
                                    self.orderNumber,    // Order ID
                                    line.sku(),          // SKU
                                    line.name(),         // Product Name
                                    line.searchfield1(), // Category
                                    line.price(),        // Price
                                    line.qty()           // Quantity
                                ]);
                            }

                            _gaq.push(['_trackTrans']);

                        } catch(err) {}

                        break;
                    case 'ua':
                        // do new universal analytics

                        try {

                            // add transaction details (Universal)
                            ga('require', 'ecommerce'); // Load the ecommerce plug-in.

                            ga('ecommerce:addTransaction', {
                                'id':self.orderNumber(),                   // Transaction ID. Required
                                'affiliation': ofConfig.t_tracking_company, // Affiliation or store name
                                'revenue':self.orderTotal(),               // Grand Total
                                'shipping':self.shippingTotal(),           // Shipping
                                'tax':self.taxTotal()                      // Tax
                            });

                            for(var i = 0; i < self.detailLines().length; i++) {
                                var line = self.detailLines()[i];

                                // add order item details (Universal)
                                ga('ecommerce:addItem', {
                                    'id': self.orderNumber(),         // Transaction ID. Required.
                                    'name': line.name(),              // Product name. Required.
                                    'sku': line.sku(),                // SKU/code.
                                    'category': line.searchfield1(),  // Category or variation.
                                    'price': line.price(),            // Unit price.
                                    'quantity': line.qty()            // Quantity.
                                });
                            }

                            ga('ecommerce:send');



                        } catch(err) {}

                        break;
                    case 'uae':
                        // do new universal analytics with enhanced ecommerce

                        try {


                            for(var i = 0; i < self.detailLines().length; i++) {
                                var line = self.detailLines()[i];

                                ga('ec:addProduct', {                // Provide product details in an productFieldObject.
                                    'id': line.sku(),                // Product ID (string).
                                    'name': line.name(),             // Product name (string).
                                    'category': line.searchfield1(), // Product category (string).
                                    'brand': line.searchfield5(),    // Product brand (string).
                                    'variant': '',                   // Product variant (string).
                                    'price': line.price(),           // Product price (currency).
                                    'coupon': self.couponCode(),     // Product coupon (string).
                                    'quantity': line.qty()           // Product quantity (number).
                                });
                            }

                            ga('ec:setAction', 'purchase', {               // Transaction details are provided in an actionFieldObject.
                                'id': self.orderNumber(),                  // (Required) Transaction id (string).
                                'affiliation': ofConfig.t_tracking_company, // Affiliation (string).
                                'revenue': self.orderTotal(),              // Revenue (currency).
                                'tax': self.taxTotal(),                    // Tax (currency).
                                'shipping': self.shippingTotal(),          // Shipping (currency).
                                'coupon': self.couponCode()                // Transaction coupon (string).
                            });

                            ga('send', 'pageview');

                        } catch(err) {}

                        break;
                    default:
                        break;
                }
            }
        }

        self.updateOrderAccess = function(){
            if( self.completed() || self.lifecycleStage() == 'cancelled'){
                self.allowAccountEdits( false );
                self.allowContactEdits( false );
                self.allowShaEdits( false );
                self.allowWarehouseSelection( false );
                self.allowProductAdds( false );
                self.allowShipViaEdits( false );
                self.allowPayMethodEdits( false );
                self.allowCcnChanges( false );
                self.allowPlaceOrder( false );
                self.allowQtyControls( false );
            }else if(self.superUserOrderFormMode()){
                self.allowAccountEdits(self.allowAccountEdits() && ofConfig.superUserAllowAccountEdits);
                self.allowContactEdits(self.allowContactEdits() && ofConfig.superUserAllowContactEdits);
                self.allowShaEdits(self.allowShaEdits() && ofConfig.superUserAllowShaEdits);
                self.allowWarehouseSelection(ofConfig.allowWarehouseSelection || ofConfig.superUserAllowWarehouseSelection );
                self.allowProductAdds(true);
                self.allowShipViaEdits(self.allowShipViaEdits() || ofConfig.superUserAllowShipViaEdits);
                self.allowPayMethodEdits(self.allowPayMethodEdits() || ofConfig.superUserAllowPayMethodEdits);
                self.allowCcnChanges(self.allowCcnChanges() || ofConfig.superUserAllowCcnChanges);
                self.allowPlaceOrder(self.allowPlaceOrder() || ofConfig.superUserAllowPlaceOrder);
                self.allowQtyControls( ofConfig.superUserAllowQtyControls );
            }else{
                self.allowAccountEdits( self.allowAccountEdits() && ofConfig.AllowAccountEdits );
                self.allowContactEdits( self.allowContactEdits() && ofConfig.allowContactEdits );
                self.allowShaEdits( self.allowShaEdits() && ofConfig.AllowShippingEdits );
                self.allowWarehouseSelection( ofConfig.allowWarehouseSelection );
                self.allowProductAdds( self.allowProductAdds() );
                self.allowQtyControls( false );
            }

            var inFocusTemplate = true;
            if(self.completed() && inFocusTemplate) {
                $('#focusHeaderExit').removeAttr("data-toggle");
                $('#focusHeaderExit').attr("href" , "https://coresite.cimproduction.com");
            }
        };

        self.updateOrderAccess();

        self.continueProcessingForm = function(data) {
            var bContinueProcessing = true;

            //TODO: Get this validation working using the validation plugin.
            //This is a quick 'fix' to prevent the page from processing the order action
            //when the shipping account is required but not set.
            _.each(viewModel.shipments(), function(shipment, index){
                if(ofConfig.CollectShipAccount && shipment.selectedShipVia.collectShippingAccount() && !shipment.selectedShipVia.shippingAccountId.isValid() ){
                    //form is not valid
                    scrollToSection('#shipping-account-info' + (index+1));
                    //jQuery('#shipping-account-select' + shipmentCount).addClass('control-group error');
                    bContinueProcessing = false;
                    return false;
                }
            });

            if(viewModel.selectedOrderAction != undefined && viewModel.selectedOrderAction().showPaymentMethods()) {
                //TODO: Do CC validation in a less janky way
                //This is a quick 'fix' to prevent the page from processing the order action
                //when the CC billing address info is invalid
                //Currently doesn't provide any messaging
                if(viewModel.paymentMethod.paymentType() === 'cc' && data.placeOrderActionType() == 'place') {

                    if(   ($('#ccpm_cvv2_code').is(':visible') && !$('#ccpm_cvv2_code').val())
                        || !$('#ccpm_address_input').val()
                        || !$('#ccpm_city_input').val()
                        || !$('#ccpm_country_input').val()
                        || !($('#ccpm_state_dropdown').prop('disabled') ? $('#ccpm_state_text').val() : $('#ccpm_state_dropdown').val())
                        || !$('#ccpm_zip_input').val()
                    ) {
                        // CC billing address form is not valid
                        $("#ccpm_card_billing_address_section").addClass("in").css({ "height" : "auto" });
                        $("#ccpm_card_billing_address_section :input:visible:not('button')")
                            .filter(function() { return $(this).val() == ""; })
                            .trigger("change");
                        $("#ccpm_cvv2_code").trigger("change");
                        scrollToSection('#payment_methods');
                        bContinueProcessing = false;
                        return false;
                    }
                }
                //Pretty much just following the same pattern as cc validation.
                //Need to stop the page from processing if the poNum is required and not entered.
                if(viewModel.paymentMethod.collectPO() && viewModel.paymentMethod.poRequired() && !$('#ponumber').val()) {
                    jQuery('#controlgroup_invoice_ponumber').addClass('control-group error');
                    scrollToSection('#payment_methods');
                    bContinueProcessing = false;
                    return false;
                }
            }

            //hook for adding custom validation checks
            var config = {
                continueProcessing: bContinueProcessing
            };
            runHook('cartTemplatesContinueProcessing', config);
            return config.continueProcessing;
        };

        self.processOrderAction = function(data){
            var bContinueProcessing = self.continueProcessingForm(data);

            if(bContinueProcessing){

                if( data.showComments() && viewModel.customerComment() != '' ){
                    self.saveCustomerComment();
                }

                if(data.showRecurringOrderSettings()){
                    self.saveRecurringOrderSettings();
                }

                var postData = {};
                var bPost = true;
                postData.orderActionKey = data.orderActionKey();

                if(viewModel.paymentMethod.paymentType() === 'cc' && (viewModel.selectedOrderAction != undefined && viewModel.selectedOrderAction().showPaymentMethods())) {

                    var defaultCcnChecked = $('#ccpm_default_ccn_id_selection').is(':checked');

                    if(defaultCcnChecked) {
                        postData.setDefaultCcn = 1
                    }

                    postData.ccn_key =  $('#ccpm_ccn_id').val();
                    postData.cvv     =  $('#ccpm_cvv2_code').val();
                    postData.address =  $('#ccpm_address_input').val();
                    postData.city    =  $('#ccpm_city_input').val();
                    postData.country =  $('#ccpm_country_input').val();
                    postData.state   =  $('#ccpm_state_dropdown').prop('disabled') ? $('#ccpm_state_text').val() : $('#ccpm_state_dropdown').val();
                    postData.zip     =  $('#ccpm_zip_input').val();
                    postData.tsm_id  =  viewModel.paymentMethod.merchantId();

                }else if(viewModel.paymentMethod.paymentType() === 'paypal' && data.placeOrderActionType() == 'place'){
                    bPost = false;
                    postPayPal(data.orderActionKey());
                }

                var postOptions = {
                    data: postData,
                    error: function() {
                        alert('Error Processing Order Action');
                    }
                }

                var scrollToId = 'checkout';

                runHook('cartTemplateOverridePostOptions', { postOptions: postOptions, data: data, self: self });

                if (bPost){
                    if ($.active > 0) {
                        viewModel.processing(true);
                        $( document ).one("ajaxStop", function(){
                            postInfo(postOptions, 'processOrderAction', scrollToId);
                        });
                    }
                    else {
                        postInfo(postOptions, 'processOrderAction', scrollToId);
                    }
                }
            }
        };

        self.saveRecurringOrderSettings = function(){
            var postData = [];
            var order = [];

            var orderKey = viewModel.orderKey();

            var roRunDate = viewModel.roRunDate();
            var roRecCase = viewModel.roRecCase();
            var roRecQty  = viewModel.roRecQty();
            //This has to be set before processOrderAction or the OO will "unset" the values above when the record_type isn't set to recurring.
            var recordType = "recurring";


            order.push({
                "o_key" : orderKey,
                "ro_rundate": roRunDate,
                "ro_rec_case": roRecCase,
                "ro_rec_qty": roRecQty,
                "record_type": recordType
            });

            postData =
            {
                "Tables": [
                    {
                        "TableName"           : "orders",
                        "TableKeyField"       : "o_key",
                        "UserKeyField"        : "o_key",
                        "UserKeyIsPrimaryKey" : "True",
                        "Data"                : order
                    }
                ]
            }

            jQuery.ajax({
                url: 'payment.asp' + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=postLogicJSON&randomnum=' + new Date().getTime()
                , data: "postLogicJSON=" + encodeURIComponent(JSON.stringify(postData))
                , cache: false
                , type: 'POST'
                , dataType: 'json'
                , success: function(data,status,request){
                    viewModel.roRunDate(roRunDate);
                    viewModel.roRecCase(roRecCase);
                    viewModel.roRecQty(roRecQty);
                }
                , error: function(data) {
                    alert('Error posting Recurring Order Settings');
                }
                , complete: function(data) {
                }
            });
        };

        self.saveCustomerComment = function(){

            var postData = [];
            var noteBook = [];
            var note = [];
            var order = [];

            var notebookTableName = ofConfig.useNewNotebooks ? 'Notebooks' : 'note_books';
            var notebookKeyField = ofConfig.useNewNotebooks ? 'Id' : 'nb_key';
            var notebookRefField = ofConfig.useNewNotebooks ? 'ReferenceId' : 'ref_id';
            var ref_id = self.noteBook().refId || generateRefId();
            var n_key = utils.createGuid();

            if(ofConfig.useNewNotebooks) {
                var notebookId = parseInt(self.noteBook().id || 0) || ref_id;

                noteBook.push({
                    "Id": notebookId,
                    "ReferenceId": notebookId
                });

                order.push({
                    "o_key" : self.orderKey(),
                    "NotebookId": notebookId
                });

                note.push({
                    "n_key"          : n_key,
                    "ref_id"         : generateRefId(),
                    "NotebookId"     : notebookId,
                    "a_id"           : ofConfig.superUserAccountKey || ofConfig.AccountKey,
                    "c_id"           : ofConfig.superUserCustomerKey || ofConfig.CustomerKey,
                    "create_date"    : new Date().toDateString(),
                    "external_notes" : self.customerComment()
                });

            } else {
                var nb_key = self.noteBook().nbKey || utils.createGuid();

                order.push({
                    "o_key" : self.orderKey(),
                    "nb_id" : nb_key
                });

                noteBook.push({
                    "nb_key"        : nb_key,
                    "ref_id"        : ref_id,
                    "create_date"   : new Date().toDateString(),
                    "book_type"     : 'order',
                    "resource_c_id" : ofConfig.superUserCustomerKey || ofConfig.CustomerKey
                });

                note.push({
                    "n_key"          : n_key,
                    "ref_id"         : generateRefId(),
                    "nb_id"          : nb_key,
                    "a_id"           : ofConfig.superUserAccountKey || ofConfig.AccountKey,
                    "c_id"           : ofConfig.superUserCustomerKey || ofConfig.CustomerKey,
                    "create_date"    : new Date().toDateString(),
                    "external_notes" : self.customerComment()
                });
            }

            postData =
            {
                "Tables": [
                    {
                        "TableName"           : notebookTableName,
                        "TableKeyField"       : notebookKeyField,
                        "UserKeyField"        : notebookRefField,
                        "UserKeyIsPrimaryKey" : "False",
                        "Data"                : noteBook
                    },
                    {
                        "TableName"           : "orders",
                        "TableKeyField"       : "o_key",
                        "UserKeyField"        : "o_key",
                        "UserKeyIsPrimaryKey" : "True",
                        "Data"                : order
                    },
                    {
                        "TableName"           : "notes",
                        "TableKeyField"       : "n_key",
                        "UserKeyField"        : "ref_id",
                        "UserKeyIsPrimaryKey" : "False",
                        "Data"                : note
                    }
                ]
            }

            jQuery.ajax({
                url: 'payment.asp' + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=postLogicJSON&randomnum=' + new Date().getTime()
                , data: "postLogicJSON=" + encodeURIComponent(JSON.stringify(postData))
                , cache: false
                , type: 'POST'
                , dataType: 'json'
                , success: function(data,status,request){
                    viewModel.updateNoteBook(note[0]);
                    viewModel.customerComment('');
                    return data.PostedKeys[notebookTableName][0];
                }
                , error: function(data) {
                    alert('Error posting Comment');
                }
                , complete: function(data) {
                }
            });
        };

        self.updateNoteBook = function(note) {
            var item = {};

            item.internalNotes    = note.internal_notes;
            item.externalNotes    = note.external_notes;
            item.postedByName     = ofConfig.superUserName || ofConfig.customerName;
            item.postedByUsername = ofConfig.superUserUsername || ofConfig.customerUsername;
            item.createDate       = note.create_date;

            viewModel.noteBook().notes.unshift(item);
        };

        self.genericModalComplete = function(data){
            var postOptions = {
                success: function(data) {
                },
                error: function() {
                    alert('error reloading shipping accounts');
                }
            }

            postInfo(postOptions, 'getOrderJSON');
            return true;
        };

        self.removeProduct = function(data){
            if(ofConfig.bUseRemoveMsg){
                var bRemove = confirm(ofConfig.sRemoveProductMessage);
            }
            else{
                bRemove = true;
            }

            if (bRemove) {
                viewModel.processing(true);
                var itemToDelete = data;
                var removeType = itemToDelete.removeType();
                var orderDetailKey = itemToDelete.orderDetailKey();
                var instance = itemToDelete.instance();
                var sRemoveUrl = 'i_i_add_to_cart.asp?type=remove&unq=' + orderDetailKey + '&o_id=' + data.orderID() + '&modal=1';

                jQuery.ajax({
                    url: sRemoveUrl
                    , cache: false
                    , type: 'GET'
                    , success: function(data,status,request){
                        var newArray = _.remove(viewModel.detailLines(), function(line){
                            return !(line.instance() == instance);
                        });
                        viewModel.detailLines(newArray);
                        viewModel.processing(false);
                    }
                    , error: function(data) {
                        alert('Error removing item.');
                        viewModel.processing(false);
                    }
                    , complete: function(data) {
                        viewModel.processing(false);
                    }
                });
            }
        };

        self.resetProductEdits = function(editingDetailLine) {
            viewModel.detailLines()
                .forEach(function(detailLine) {
                    detailLine.editing(false);
                });
            viewModel.shipments()
                .forEach(function(shipment) {
                    shipment.details()
                        .forEach(function(detail) {
                            detail.orderDetail.editing(false);
                        });
                });
            viewModel.mainProduct(undefined);
            utils.removeActiveQuote();

            if(editingDetailLine) {
                editingDetailLine.editing(true);
            }
        }

        self.editProduct = function(data) {
            self.resetProductEdits();
            var detailLine = data;
            if(data.orderDetail) {
                detailLine = data.orderDetail;
            }
            var detailKey  = detailLine.orderDetailKey();
            var productKey = detailLine.parentProductID().trim() || detailLine.productID();

            var productInfo = {
                productKey: detailLine.productID(),
                productSku: detailLine.sku(),
                parentChildType: detailLine.commodity.parentChildType() || '',
                parentProductId: detailLine.parentProductID().trim()
            }

            self.loadProductForEdit(productInfo, detailKey, detailLine)
        }

        self.cancelEditProduct = function(data) {
            self.resetProductEdits();
        }

        self.loadProductForEdit = function(productInfo, detailLineId, detailLine) {
            viewModel.processing(true);
            self.resetProductEdits(detailLine);

            var postOptions = {
                success: function(data) {
                    var response = JSON.parse(data);
                    var product = response.product;
                    switch(product.childDisplayType) {
                        case 'input-qty':
                        case 'exploded-view':
                        case 'matrix-all':
                        case 'add-row':
                            product.childDisplayType = 'droplist'
                            break;
                        default:
                    };

                    if(!!response.childSkuMatch) {
                        oConfig.childSkuMatch = response.childSkuMatch;
                    }

                    utils.setActiveQuote(viewModel.orderKey());
                    viewModel.mainProduct(ko.mapping.fromJS(product, productMapping));
                    viewModel.addToSavedCart();
                },
                url: orderInfoPostUrl + '?o_key=' + self.orderKey() + '&p_key=' + (productInfo.parentProductId || productInfo.productKey) + '&od_key=' + detailLineId + '&sku=' + productInfo.productSku + '&ajax=true&pageaction=getProductData&modal=1',
                type: 'GET',
                error: function() {
                    alert('Error loading product data!');
                }
            }

            $.ajax({
                url      : postOptions.url,
                success  : postOptions.success,
                type     : postOptions.type,
                error    : postOptions.error,
                complete : function() { viewModel.processing(false); }
            });
        }

        self.productFinderSearchTerm = ko.observable('');

        self.productFinderUrl = ko.computed(function() {
            var searchTerm = self.productFinderSearchTerm();
            var search2 = ofConfig.productFinderSearchstring.replace(/__query__/g, searchTerm);
            return 'bulk_atc.asp?find_product=1&s=' + searchTerm + '&search2=' + search2;
        });

        self.showRemoveLink = function(data){
            if(!ofConfig.allowProductRemoves){
                return false;
            }

            var instanceKeys = viewModel.detailLines().reduce(function(instanceKeys, line) {
                if(instanceKeys.indexOf(line.instance()) == -1) {
                    instanceKeys.push(line.instance());
                }
                return instanceKeys;
            }, []);

            if(!ofConfig.allowRemoveLastItem && instanceKeys.length < 2) {
                return false;
            }

            if(data.removeType() == 'hide'){
                return false;
            }
            return true;
        };

        self.breadcrumbMarkup = ko.computed(function(){
            if(self.recordType() == 'cart') {
                return ofConfig.sPaymentHeaderLabel;
            } else if (self.recordType() == 'recurring') {
                return '<ul class="breadcrumb breadcrumb-cart"><li class="active">Recurring Order # ' + self.referenceId();
            } else {
                return '<ul class="breadcrumb breadcrumb-cart"><li class="active">' + ofConfig.SavedCartLabel + '# ' + self.referenceId() + '</li><li><i class="icon-ok"></i> Order Placed</li></ul>'
            }
        });

        self.expirationDate = ko.observable(function() {
            return new moment(self.quoteExpirationDate()).format("MM/DD/YYYY");
        }());

        self.expirationDate.subscribe(function(newExpirationDate) {
            self.buildOrderHeaderFields(["QuoteExpirationDate"]);
        });

        // Used for Google Analytics and Tag Manager, etc
         /*
        Runs when order is completed but payment page doesn't re-fresh
        - Example user pays with a credit card or bill me payment option
        */
        self.orderPlaced.subscribe(function() {
            self.postOrderToGoogleAnalytics();
            postOrderHeaderField('tracked', '1');
            self.tracked('1');
        });
        /*
        Runs when order is completed and the payment page re-freshes
        - Happens when user checks out with paypal and is re-directed back to payment page
        - with a completed order
        */
        if (self.completed() && self.tracked() != '1' ) {
            self.postOrderToGoogleAnalytics();
            postOrderHeaderField('tracked', '1');
            self.tracked('1');
         }

        addTimer("orderModelBottom");
        runHook('orderModelBottom', { self: self, order: self });
        addTimer("end order mapping");
    } // end of var Order = blah blah blah 

    function processShippingAddresses(data){
        var addressArray = data;
        var newshippingAddresses;
        if(Array.isArray(addressArray)) {
            newshippingAddresses = addressArray.map(function(item, index, arr) {
                address = new addressInfo();
                address.name(item.sha_nm);
                address.company(item.s_company || '');
                address.attention(item.attention || '');
                address.address1(item.s_add1 || '');
                address.address2(item.s_add2 || '');
                address.address3(item.s_add3 || '');
                address.address4(item.s_add4 || '');
                address.address5(item.s_add5 || '');
                address.country(item.s_country || 'USA');
                address.city(item.s_city || '');
                address.state(item.s_state || undefined);
                address.zipCode(item.s_zip || '');
                address.phone(item.s_phone || '');
                address.email(item.em || '');
                address.global(item.globaladdress || '0');
                address.opt1(item.s_opt1 || '');
                address.opt2(item.s_opt2 || '');
                address.opt3(item.s_opt3 || '');
                address.opt4(item.s_opt4 || '');
                address.opt5(item.s_opt5 || '');
                address.key(item.sha_key);
                address.editing(false);
                return address;
            });
        }

        /*
        Changing to an observable array (was an obeservable object that contained an array)
        */
        var observableAryOfSHA = ko.observableArray([]);
        newshippingAddresses.forEach(function(obj){
            observableAryOfSHA.push(ko.mapping.fromJS(obj, shippingAddressMappingOptions));
        });

        return observableAryOfSHA; //ko.mapping.fromJS(newshippingAddresses, shippingAddressMappingOptions);
    }

    var orderMapping = {
        create: function(options) {
            var newOrder = new Order(options.data);

            return newOrder; // new Order(options.data);
        }
    }

    //Build Json for order header field and optional additional tables.
    //Pass the Json to the Post Logic Ajax function
    var postOrderHeaderField = function(sOrderField, viewModelProperty, extraTablesJson, callbacks) {
        console.log(sOrderField);
        var postData = {};
        var order = [];

        order = [{
            "o_key" : ofConfig.OKey
        }];

        order[0][sOrderField] = viewModelProperty;

        postData =
        {
            "Tables": [
                {
                    "TableName"           : "orders",
                    "TableKeyField"       : "o_key",
                    "UserKeyField"        : "o_key",
                    "UserKeyIsPrimaryKey" : "True",
                    "Data"                : order
                }
            ]
        };

        //Optional additional tables on the order
        if (!!extraTablesJson) {
            postData["Tables"].push(extraTablesJson);
        }

        self.postLogicJsonAjax(postData, false, callbacks);
    };

    var postOrderDetailFields = function(sOrderDetailKey, sDetailFields, viewModelProperties, callbacks) {

        var postData = {};
        var orderLine = [];

        orderLines = [{
            "od_key" : sOrderDetailKey
        }];

        for(var i = 0; i < sDetailFields.length; i++){
            orderLines[0][sDetailFields[i]] = viewModelProperties[i];
        }

        postData =
        {
            "Tables": [
                {
                    "TableName"           : "order_detail",
                    "TableKeyField"       : "od_key",
                    "UserKeyField"        : "od_key",
                    "UserKeyIsPrimaryKey" : "True",
                    "Data"                : orderLines
                }
            ]
        };
        self.postLogicJsonAjax(postData, false, callbacks);
    };

    //Posts Json directly to table(s) using Post Logic
    //Should be used for fields that do not affect other properties in the ViewModel (i.e. text areas)
    //No actions on success.
    var postLogicJsonAjax = function(postData, getOrderJSON, callbacks) {
        callbacks = callbacks || {};

        jQuery.ajax({
            url: 'payment.asp' + '?o_key=' + ofConfig.OKey + '&getorderJSON=' + getOrderJSON + '&ajax=true&pageaction=postLogicJSON&randomnum=' + new Date().getTime(),
            data: "postLogicJSON=" + encodeURIComponent(JSON.stringify(postData)),
            cache: false,
            type: 'POST',
            dataType: 'json',
            success: callbacks.success,
            error: function(jqXHR, textStatus, errorThrown) {
                if (typeof callbacks.error == 'function') {
                    callbacks.error(jqXHR, textStatus, errorThrown);
                } else {
                    alert('Error posting to ' + (postData["Tables"][0]["TableName"] || "postLogicJsonAjax") + '.');
                }
            },
            complete: callbacks.complete
        });
    };


    var apiRoutedPageActions = [
        /*
        // can't be converted yet
        'placeOrder',
        'processOrderAction',
        */
        'setSha',
        'setCCN',
        'setPmId',
        'setCoupon',
        'setGiftCertCode',
        'setOrderHeaderFields',
        'setRequestedShipDate',
        'setShippingPrice',
        'getOrderJSON',
        'resetShippingPrice',
        'setShipmentShipVia'
    ];
    
    apiRoutedPageActions = apiRoutedPageActions.concat([
        'updateShipToAddress',
        'setOrderDetailFields',
        'assignOwnership'
    ]);
    

    var postInfo = function(ajaxOptions, pageAction, scrollToId, model) {
        if(!model) {
            model = viewModel;
        }

        model.activeAjaxRequestCount(model.activeAjaxRequestCount() + 1);

        model.processing(true);

        model.errorMessages.removeAll();

        var existingSuccess = ajaxOptions.success;
        var existingError = ajaxOptions.error;
        var existingComplete = ajaxOptions.complete;

        var querystring = ajaxOptions.url
            ? ajaxOptions.url.substring(ajaxOptions.url.indexOf('?'))
            : '?o_key=' + viewModel.orderKey()
        var apiUrl = orderInfoPostApiUrl + pageAction + querystring;
        var comUrl = orderInfoPostUrl + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=' + pageAction;

        if (apiRoutedPageActions.includes(pageAction)) {
            ajaxOptions.url = apiUrl;
        } else if (!ajaxOptions.url) {
            ajaxOptions.url = comUrl;
        }

        if(!ajaxOptions.type) {
            ajaxOptions.type = 'POST';
        }

        ajaxOptions.success = function(data) {
            var response = JSON.parse(data);
            if(Array.isArray(response) && Object.keys(response[0].Errors).length > 0) {
                for (var msg in response[0].Errors) {
                    if(response[0].Errors.hasOwnProperty(msg)) {
                        scrollToId = 'errorList';

                        model.errorMessages.push(
                            {
                                "errorType": msg,
                                "message": response[0].Errors[msg]
                            }
                        );
                    }
                }
            }

            ko.mapping.fromJS(response[1], orderMapping, model);

            model.updateOrderAccess();
            if(viewModel.isOverLineLimit()){
                model.shippingComplete(true);
            }
            if(typeof existingSuccess === 'function') {
                existingSuccess(data);
            }
            
            _.each(model.itemShipToMap(), function(item){
                item.qty.subscribe(function () { 
                    model.isMinimumOrderTotalMet(checkOrderTotal(model));
                });   
            });

            if(scrollToId) {
                model.showConfirmationMessage(true);
                scrollToSection('#' + scrollToId);
            }
            
            model.detailLines().forEach(function(detailLine) {
                // We can't debounce/trottle an observable
                // so we add a computed to track qty changes.
                // We use this in a subscription to call
                // update cart to update qty change in bulk atc
                // to avoid loading the qty change without posting
                // and updating the entire order model (for perf)
                detailLine.qtyTracker = ko.computed(function() {
                    return detailLine.qty();
                }).extend({throttle: 500});
                detailLine.qtyTracker.subscribe(function (newQty) {
                    model.postQtyUpdate();
                }, detailLine);
                detailLine.workerPriceTracker = ko.computed(function() {
                    return detailLine.price();
                }).extend({throttle: 500});
                detailLine.workerPriceTracker.subscribe(function (newQty) {
                    model.setWorkerPriceOverride(detailLine);
                }, detailLine);
                detailLine.workerQtyLimitsTracker = ko.computed(function() {
                    return {
                        removeType: detailLine.removeType(),
                        minQty: detailLine.minQty(),
                        maxQty: detailLine.maxQty(),
                        qtyIncrement: detailLine.qtyIncrement()
                    };
                }).extend({throttle: 500});
                detailLine.workerQtyLimitsTracker.subscribe(function (newValue) {
                    model.setWorkerQtyLimits(detailLine);
                });
            });
        };

        ajaxOptions.error = function(jqXHR, textStatus, errorThrown) {    
            if (ajaxOptions.url != comUrl) {
                // if API call fails, retry with COM AJAX
                ajaxOptions.url = comUrl;
                $.ajax({
                    url: orderInfoPostUrl + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=logError&url=' + encodeURIComponent(apiUrl) + '&method=' + pageAction + '&message=API error (' + jqXHR.status + ')',
                    success: function() {
                    },
                    error: function() {
                    }
                });
                $.ajax(ajaxOptions);
                return;
            }
            if(typeof existingError === 'function') {
                existingError(); //data is not defined
            }
        };

        ajaxOptions.complete = function() {
            runHook('postInfoAjaxCompleteFunction', { model: model, ajaxOptions: ajaxOptions, pageAction: pageAction, scrollToId: scrollToId });
            if(typeof existingComplete === 'function') {
                existingComplete();
            }
            model.activeAjaxRequestCount(model.activeAjaxRequestCount() - 1);
            if(model.activeAjaxRequestCount() < 1) {
                model.processing(false);

                /* EJ - 2016-11-14
                   Ugly hack to get around ko.mapping not initializing the Account
                   property correctly when re-mapping on existing object.  I think
                   it may have to do with manually converting the Account property
                   to a validatedObservable the first time through.
                */
                fixUpNulls(model.Account());
            }
        };

        $.ajax(ajaxOptions);
    }

    var fixUpNulls = function(account) {
        for(var prop in account) {
            if(account.hasOwnProperty(prop) && typeof account[prop] === 'function') {
                if(account[prop]() === null || account[prop]() === 'null') {
                    account[prop]('');
                }
            }
        }
    }

    var postPayPal = function(orderActionKey) {
        viewModel.processing(true);

        jQuery.ajax({
            url: 'payment.asp' + '?paypal_order_submit=1&oa_id=' + orderActionKey + '&o_key=' + viewModel.orderKey() + '&randomnum=' + new Date().getTime()
            , data: "o_key=" + viewModel.orderKey()
            , cache: false
            , type: 'POST'
            , dataType: 'json'
            , success: function(data){
				if(!data.status && data.message != ''){
					viewModel.errorMessages.push(
                            {
                                "errorType": "payment_methods",
                                "message": data.message
                            }
                        );
					viewModel.processing(false);
				}
                else if(data.url != ''){
                    document.location = data.url;
                }

            }
            , error: function(data) {
                alert('Error attempting PayPal checkout');
                viewModel.processing(false);
            }
            , complete: function(data) {
            }
        });
    }

    var addFromProductFinder = function(productInfo) {
        viewModel.productFinderSearchTerm('');

        var productInfo = {
            productKey: productInfo.key,
            productSku: productInfo.sku,
            parentChildType: productInfo.parent_child_type,
            parentProductId: productInfo.parent_p_id
        }

        viewModel.loadProductForEdit(productInfo, '');
    }

    var checkOrderTotal = function(model){
        var orderTotalValid = true;
        var subTotal = 0;
        if(ofConfig.useMinimumOrderTotal && !model.completed()){
            if(model.useMultiShipEditUI && model.useMultiShipEditUI()){
                _.each(model.itemShipToMap(), function(item){
                    subTotal += (item.qty() * item.getPrice());
                });
                console.log('itemShipToMap');
            }else if(model.itemsOnOrder){
                _.each(model.itemsOnOrder(), function(item){
                    subTotal += (item.qty() * item.price());
                });
            }else{
                var subTotal = model.productTotal();
            }
            var minimumTotal = ofConfig.minimumOrderTotal;

            if(ofConfig.useAccountMinimumOrderTotal && ofConfig.accountMinimumOrderTotal > 0){
                minimumTotal = ofConfig.accountMinimumOrderTotal;
            }
            if(subTotal < minimumTotal){
                orderTotalValid = false;
            }
        }
        return orderTotalValid;
    }

    $(function() {
        if(getOriginalPageName() !== 'bulk_atc.asp') {
            addGlobalModalCompletionHandler($('#find_product'), addFromProductFinder);
        }

        runHook('cartTemplatesDocumentReady', {self: viewModel});
    });

    addTimer("end of ko model");
</script>

<script type="text/javascript">
	function isComplex(product) {
        return product.is_kit_container ||
            product.use_config_questions ||
            product.show_config_sections ||
            product.use_cart_options ||
            product.addon_prod_show ||
            ((oConfig.useSalesUom || ofConfig.showUom) && product.uom_sales_conversion != 1)
    }

    function handleSkuSubmission(sku, state) {
        $('#handle-modal-exit').val(true);

        var sku = _.trim(viewModel.productFinderSearchTerm());
        //var $sku = $('#sku_entry');
        //var sku = _.trim($sku.val());
        if (sku) {
            var request = new ProductRequest('page_entry', {
                sku: sku,
                state: state
            });
            return processProductRequests([request]);
        } else {
            return $.when();
        }
    }

    function processProductRequests(requests) {
        var def = $.Deferred();

        loadProducts(requests)
            .done(function () {
                if(!requests[0].product) {
                    openProductFinder(requests[0].sku);
                } else {
                    if(isComplex(requests[0].product)){
                        openQuickAdd(requests[0].product.p_key);
                    }else{
                        if(requests[0].product.calc_inv_show_cart == undefined || requests[0].product.calc_inv_show_cart) {
                            autoAddToCart(requests[0].product);
                        } else {
                            $('#sku_entry').val('');
                            alert("This product is currently unavailable.");
                        }
                    }
                }
            })
            .fail(_.bindKey(def, 'reject'));

        return def.promise();
    }

    function loadProductsByAjax(pageaction, prop, requests) {
        var def;

        if (requests.length) {
            def = $.Deferred();
            var config = {
                url: 'bulk_atc.asp?modal=1',
                dataType: 'JSON',
                data: {
                    pageaction: pageaction,
                    items: _.pluck(requests, prop)
                }
            };

            runHook('loadProductsByAjaxConfig', config);

            $.ajax(config)
                .done(function (data) {
                    if (data.items) {
                        def.resolve(data.items);
                    } else {
                        def.reject();
                    }
                })
                .fail(function () {
                    def.reject();
                });

            def.fail(function () {
                console.error('Failed to fetch product info.');
            });
        } else {
            def = $.when([]);
        }

        return def.promise();
    }

    function openProductFinder(searchTerm) {
        //open the search results and pass in the term.
        var baseUrl = fncProcessUniversalSearch(searchTerm, false) + '&modalaction=addProduct&modal=1';
        modal.open({
            "url"     : baseUrl,
            "size"    : "full",
            "title"   : "Add Products",
            "complete": function() { viewModel.genericModalComplete }
        });
    }

    function openQuickAdd(productKey){
        //open detail page for quick add.
        var baseUrl = '/pc_product_detail.asp?p_key=' + productKey + '&quickadd=true';
        modal.open({
            "url"     : baseUrl,
            "size"    : "small",
            "title"   : "Add Products",
            "complete": function() { viewModel.genericModalComplete }
        });
    }

    function autoAddToCart(product){
        toggleLoadingWidget(true);
        productKey = product.p_key;
        var productInfo = {};
        productInfo['keys'] = productKey;
        productInfo['qty_' + productKey] = product.min_qty || 1;
        productInfo['pw_id_' + productKey] = product.pw_id || oConfig.defaultWarehouse;
        productInfo['parent_p_id_' + productKey] = product.parent_p_id;
        productInfo.product = product; //add for the hook's use
        runHook('autoAddToCartProductConfig', productInfo);
        delete productInfo.product; //remove before POST
        return $.ajax({
            url: 'i_i_add_to_cart.asp?' + $.param({
                type: 'ajaxadd',
                o_key: viewModel.orderKey(),
                modal: '1'
            }),
            type: 'POST',
            data: productInfo
        })
        .done(function(){ $('#sku_entry').val('')})
        .done(function(){ viewModel.genericModalComplete() } )
        .done(function(){ toggleLoadingWidget(false)})
    }

    function loadProducts(requests) {
        var requestPartitions = _.partition(requests, 'key');
        var requestsWithKey = requestPartitions[0];
        var requestsWithoutKey = requestPartitions[1];

        var def = $.Deferred();
        toggleLoadingWidget(true);

        $.when(
            loadProductsByAjax('products_by_key', 'key', requestsWithKey),
            loadProductsByAjax('products_by_sku', 'sku', requestsWithoutKey)
        )
            .done(function (productsFromKeys, productsFromSkus) {
                var products = productsFromKeys.concat(productsFromSkus);

                _.each(requests, function (request) {
                    request.product = _.find(products, _.bindKey(request, 'matchesProduct'));
                });

                toggleLoadingWidget(false);
                def.resolve(products)
            })
            .fail(_.bindKey(def, 'reject'));

        return def.promise();
    }

	// Represents a request to add a product to the table.
	// The data argument must contain a product property or a sku property.
	function ProductRequest(source, data) {
		'use strict';
		var self = this;

		self.matchesProduct = function(product) {
            var match = self.key ? product.p_key === self.key : product.sku.toLowerCase() === self.sku.toLowerCase();
            var config = {
                            match: match,
                            self: self,
                            product: product
                        };
            runHook('customProductRequestMatching', config);
			return config.match;
		};

		self.source = source;
		self.product = data.product;
		self.state = data.state;
		self.price = data.price;
		self.sku = self.product ? self.product.sku : data.sku;
		self.key = self.product ? self.product.p_key : data.key;
	}

	// Represents the result of processing a ProductRequest.
	function ProductResponse(request, prompt, error) {
		'use strict';
		var self = this;

		self.request = request;
		self.prompt = prompt;
		self.error = error;
	}

    var loadSkusFromPrefix = _.memoize(function(prefix) {
        var config = {
            url: 'bulk_atc.asp?modal=1',
            dataType: 'JSON',
            data: {
                pageaction: 'sku_list',
                prefix: prefix
            }
        };

        runHook('loadSkusFromPrefixAjaxConfig', config);

        return $.ajax(config)
        .then(function (data) {
            return data.items;
        });
    });

    function getSkuList(query, process) {
        var prefix = query.slice(0, 1);
        loadSkusFromPrefix(prefix).done(process);
    }

    function initSkuAutocomplete($input) {
        var source = getSkuList;

        $input.typeahead({
            items: 8,
            minLength: 1,
            source: source,
            // Contrary to the docs, the default sorter does not put exact matches first.
            sorter: function (items) {
                var lowerQuery = this.query.toLowerCase();

                return _.sortBy(items, function (item) {
                    var lowerItem = item.toLowerCase();

                    if (lowerItem === lowerQuery) {
                        return 0;
                    } else if (!lowerItem.indexOf(lowerQuery)) {
                        return 1;
                    } else {
                        return 2;
                    }
                });
            },
            updater: function (sku) {
                // Delay the form submission until the input is updated. An event listener is
                // required since that update utilizes the return value of this function.
                $input.one('change', function () {
                    $('#add_item_form').submit();
                });
                return sku;
            }
        });
    }

    ko.bindingHandlers.autocompleteSku = {
        init: function(element, valueAccessor, allBindingsAccessor) {
            var $el = $(element);

            initSkuAutocomplete($el);
        }
    };

    ko.bindingHandlers.executeOnEnter = {
        init: function (element, valueAccessor, allBindings, viewModel) {
            var callback = valueAccessor();
            $(element).keypress(function (event) {
                var keyCode = (event.which ? event.which : event.keyCode);
                if (keyCode === 13) {
                    callback.call(viewModel);
                    return false;
                }
                return true;
            });
        }
    };
</script>

<script type="text/html" id="cart.billingSection">
    <!-- ko template: 'cart.superUserOrderFormButton'--><!-- /ko -->
    <div id="checkout_billing" class="checkout__billing" data-bind="with: viewModel">
        <div class="checkout-section-body">
            <div class="checkout-section-inner">
                <!-- ko template: { name: 'cart.billingSummary' } --> <!-- /ko -->
                <!-- ko template: { name: 'cart.billingForm' } --> <!-- /ko -->
            </div>
        </div>
        <div class="checkout-section-footer" data-bind="visible: showBillingEdit() && !orderPlaced()">
            <button
                type="button"
                id="btn_continue_shipping"
                class="btn btn-primary pull-right"
                data-target="checkout_shipping"
                data-bind="
                    click: toggleShowBillingEdit,
                    attr: { disabled: !viewModel.billingSectionValid() }
                ">
                Continue Checkout
            </button>
        </div>
    </div>
    <!-- ko template: { name: 'credits', if: viewModel.showCredits } --><!-- /ko -->
</script>

<script type="text/html" id="cart.printButton">
    <button type="button" class="btn print-btn" onclick="window.print();">
        <i class="icon-print"></i> Print
    </button>
</script>

<script type="text/html" id="cart.continueShoppingButton">
    <a type="button" class="btn print-btn" data-bind="attr: {'href': buildContinueShoppingUrl() }">
        <i class="icon-shopping-cart"></i> Continue Shopping
    </a>
</script>

<script type="text/html" id="cart.superUserOrderFormButton">
    <!-- ko if: ofConfig.isModal -->
        <div class="pull-right">
            <button type="button" class="btn btn-primary" data-bind="click: viewModel.returnToPendingOrders">
                <i class="icon-chevron-left"></i> Return to <span data-bind="text: ofConfig.SavedCartLabel"></span>s
            </button>
            &nbsp;&nbsp;
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.detailSection">
    <div id="checkout_details" class="checkout-section active completed">

        <div class="checkout-section-body">
            <div id="shipping_address_summary" >


                <!-- ko template: {
                    name: 'cart.shippingActions',
                    if: !viewModel.shippingComplete() } -->
                <!-- /ko -->

                <!-- ko template: {
                    name: 'cart.assignItemsToShipTos',
                    data: itemsOnOrder,
                    if : ofConfig.amazonView && viewModel.useMultiShipEditUI() && !viewModel.shippingComplete()  && !viewModel.completed() } -->
                <!-- /ko -->

                <!-- ko template: {
                    name: 'cart.itemsOnOrderSelection',
                    data: itemsOnOrder,
                    if :  ofConfig.invView & viewModel.useMultiShipEditUI() && !viewModel.shippingComplete()  && !viewModel.completed() } -->
                <!-- /ko -->

                <!-- ko template: {
                    name: 'cart.itemShipToMapPreview',
                    data: itemShipToMap,
                    if :  ofConfig.invView & viewModel.useMultiShipEditUI() && !viewModel.shippingComplete()  && !viewModel.completed() } -->
                <!-- /ko -->

                <!-- ko template: {
                    name: 'cart.selectShipTo',
                    data: $data,
                    if : !viewModel.useMultiShipEditUI() && !viewModel.shippingComplete() && !viewModel.completed() }-->
                <!-- /ko -->

            </div>
        </div>
    </div>
     <div class="checkout-section-footer" data-bind="visible: (!orderPlaced() && !viewModel.shippingComplete() ) && !(!viewModel.billingSectionValid() || $data.detailLines().length == 0)">
        <button 
            type="button" 
            id="btn_continue_shipping" 
            class="btn btn-primary pull-right" 
            data-target="checkoutShipping" 
            data-bind="
                attr: { 'disabled': !viewModel.isMinimumOrderTotalMet() },
                click: allocateShipments
            ">
            Continue Checkout
        </button>
    </div>
</script>

<script type="text/html" id="cart.shippingActions">
    <!-- ko if: ofConfig.allowUserCreatedShipments && detailLines().length > 0-->
        <ul class="nav nav-tabs shipping-actions">
                <li data-bind="css: { active: !viewModel.useMultiShipEditUI() }">
                    <a href="#" data-bind="click: viewModel.useMultiShipEditUI() ? viewModel.toggleMultiShip : null">Single<span class="hidden-xs"> Address</span></a>
                </li>

                <li data-bind="css: { active: viewModel.useMultiShipEditUI() }">
                    <a href="#" data-bind="click: viewModel.useMultiShipEditUI() ? null : viewModel.toggleMultiShip">Multiple<span class="hidden-xs"> Addresses</span></a>
                </li>
                <li class="shipping-actions__button" data-bind="if: ofConfig.bAllowShipToAdds && !viewModel.shippingComplete()  && !viewModel.completed()">
                    <!-- ko template: 'cart.addAddressButton' --><!-- /ko -->
                </li>
        </ul>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.productQuickAdd">
    <div class="quick-add u-checkout-well">
        <h3 class="u-checkout-well__title">Add Products</h3>
        <!-- ko if: !viewModel.isMinimumOrderTotalMet() -->
            <span data-bind="html: ofConfig.minimumOrderTotalMessage.replace('<$>', ofConfig.minimumOrderTotal)"></span>
        <!-- /ko -->
        <div class="quick-add__wrapper">

            <div class="quick-add__product-select">

                <div class="form-buttons input-append -autocomplete">
                    <label for="sku">Enter a SKU</label>
                    <input type="text" id="sku_entry"
                        data-bind="textInput: viewModel.productFinderSearchTerm,
                                autocompleteSku, 
                                executeOnEnter: handleSkuSubmission"
                        name="sku"
                        class="quick-add__sku"
                        placeholder="SKU"
                        autocomplete="off"
                        autocapitalize="off"
                        autocorrect="off">
                    <a href="#0" id="sku_submit"
                        data-bind="click: handleSkuSubmission"
                        class="btn"
                        tabindex="-1">
                        Add
                    </a>

                </div>
                <div class="form-buttons input-append">
                    <label><strong> or </strong></label>
                </div>
                <!-- ko if: viewModel.allowProductAdds() && ofConfig.showProductAddDropdown -->
                    <!-- ko template: 'cart.addProductButton'--><!-- /ko -->
                <!-- /ko -->
            </div>
        </div>
    </div>

    <div class="quick-add__config u-checkout-well"
        data-bind="
            visible: viewModel.mainProduct() && !!!viewModel.mainProduct().configuratorEditData,
            if: viewModel.mainProduct() && !!!viewModel.mainProduct().configuratorEditData
        " >
            <h3 class="u-checkout-well__title">Configure Product</h3>
            <strong data-bind="html: viewModel.mainProduct().selectedProduct().name() || viewModel.mainProduct().name()"></strong>
            <!-- ko template: { name: 'catalog.detail_info', data:viewModel.mainProduct  } --><!-- /ko -->
            <div
                data-bind="if: viewModel.mainProduct"
                class="detail-child-selector">
                    <span
                        data-bind="template: { name: 'catalog.child_selectors',
                                if: viewModel.mainProduct().childSelectors,
                                data: viewModel.mainProduct().childSelectors }"></span>
            </div>
            <!-- ko template: { name:'catalog.atc_full', data:viewModel.mainProduct().selectedProduct, if:viewModel.mainProduct } --><!-- /ko -->
        <div style="clear:both;"></div>
    </div>
</script>

<script type="text/html" id="cart.shippingSection">
    <div id="checkout_shipping" class="checkout-section active completed" data-bind="with: viewModel">
        <!-- ko if: viewModel.shippingComplete -->
            <div id="checkout_review" class="checkout__review">

                <!-- ko template: { name: 'cart.confirmation' } --><!-- /ko -->

                <!-- <h1 class="checkout__title">Checkout</h1> -->

                <!-- ko template: { name: 'cart.productQuickAdd', if: viewModel.allowProductAdds() && ofConfig.showProductQuickAddInFinalStep } --><!-- /ko -->
                <!-- ko template: { name: 'cart.shipmentList', if: viewModel.allowShipViaEdits() } --> <!-- /ko -->
                <!-- ko template: { name: 'cart.shipmentSummaryList', if: !viewModel.allowShipViaEdits() } --> <!-- /ko -->
                <!-- ko if: viewModel.shippingComplete() -->

                    <div
                        class="u-checkout-well checkout-shipping__coupon-certificate u-card"
                        data-bind="visible: !viewModel.completed() && ((ofConfig.showCoupon && ofConfig.showCouponEntryInline) || (ofConfig.showGiftCertificate && ofConfig.showGiftCertificateEntryInline)) && viewModel.allowPayMethodEdits()">

                        <h3 class="checkout-review__fieldset-content u-checkout-well__title" data-bind="visible: !orderPlaced() && allItemsAllocated()">
                            Coupons and Gift Certificates
                        </h3>
                        <!-- ko template: { name: 'cart.couponEntry', if: ofConfig.showCoupon && ofConfig.showCouponEntryInline && viewModel.allowPayMethodEdits() } --><!-- /ko -->
                        <!-- ko template: { name: 'cart.giftCertificateEntry', if: ofConfig.showGiftCertificate && ofConfig.showGiftCertificateEntryInline && viewModel.allowPayMethodEdits() } --><!-- /ko -->
                    </div>

                    <!-- ko template: { name: 'cart.abovePaymentMethods' } --><!-- /ko -->

                    <fieldset class="checkout-review__fieldset u-checkout-well" id="payment_methods" data-bind="visible: !!$data.selectedOrderAction && $data.selectedOrderAction().showPaymentMethods() && !completed()">

                        <h3 class="checkout-review__fieldset-content u-checkout-well__title" data-bind="visible: !orderPlaced() && allItemsAllocated()">
                            Secure Payment Methods
                        </h3>

                        <!-- ko template: { name: 'cart.errorList', data: _.filter(errorMessages() , function (error) { return error.errorType == 'payment_methods'; }) } --><!-- /ko -->
                        <div class="form-horizontal checkout-review__fieldset-content" data-bind=" if: viewModel.allowPayMethodEdits() && viewModel.payMethods().length">
                            <!-- ko template: { name: 'cart.paymentMethods', afterRender: initCCForm  } --><!-- /ko -->
                        </div>
                        <div class="alert alert-warning" data-bind="visible: !viewModel.payMethods().length">
                            <div data-bind="html: ofConfig.sPaymentMethodMissingError"></div>
                            <div data-bind="if: ofConfig.bIsValidIp || ofConfig.isSuperUserSession">[ No Payment Methods Found. ]</div>
                        </div>
                        <!-- ko if: !viewModel.allowPayMethodEdits() && !viewModel.completed() -->
                        <div class="well checkout-review__fieldset-content">
                            <!-- ko template: 'cart.paymentMethodSummary' --><!-- /ko -->
                        </div>
                        <!-- /ko -->

                    </fieldset>

                    <fieldset class="checkout-review__fieldset u-checkout-well" id="controlgroup_quoteinfo" data-bind="visible: (recordType() != 'cart' && ofConfig.showExpirationDate) && ((superUserOrderFormMode() && ofConfig.superUserAllowExpirationDateEdits) || viewModel.isValidDate(expirationDate()))">
                        <h3 class="checkout-review__fieldset-content u-checkout-well__title">
                            Quote Information
                        </h3>
                        <div class="form-horizontal checkout-review__fieldset-content">
                            <!-- ko template: { name: 'cart.expirationDate', if: recordType() != 'cart' && ofConfig.showExpirationDate } --><!-- /ko -->
                        </div>
                    </fieldset>

                    <fieldset class="checkout-review__fieldset u-checkout-well" id="controlgroup_recurring" data-bind="visible: !viewModel.completed() && ((selectedOrderAction() && selectedOrderAction().showRecurringOrderSettings()) || viewModel.recordType() == 'recurring' ) ">
                        <div class="checkout-review__fieldset-content">
                            <!-- ko template: { name: 'cart.recurringDetails' } --><!-- /ko -->
                        </div>
                    </fieldset>

                    <span class="checkout-summary__order-total -hidden-desktop">
                        <!-- ko template: { name: 'cart.checkoutSummary' } --><!-- /ko -->
                    </span>

                    <!-- ko template: { name: 'cart.aboveOrderActions' } --><!-- /ko -->

                    <fieldset class="checkout-review__fieldset u-checkout-well" data-bind="visible: !viewModel.completed(), if: ofConfig.showOrderActionsInline">
                        <h3 class="checkout-review__fieldset-content u-checkout-well__title" data-bind="if: viewModel.allowPlaceOrder() && shippingComplete() && paymentMethodID(), visible: orderActions().length > 1">
                            Choose an Order Action
                        </h3>

                        <!-- ko if : ofConfig.showOrderActionsInline && !viewModel.completed() -->
                            <!-- ko template: { name: 'cart.orderActions', if: shippingComplete() && paymentMethodID() && orderActions().length > 0 } --><!-- /ko -->

                            <div class="checkout-review__fieldset-content" data-bind="if: orderActions().length == 0 && shippingComplete() && paymentMethodID()">
                                <div class="alert alert-info">There are no actions available at this time.</div>
                            </div>

                        <!-- /ko -->

                        <!--ko template: { name: 'cart.noteBookNotes', if : viewModel.noteBook().notes().length > 0 && completed()  } --><!-- /ko -->

                    </fieldset>
                <!-- /ko -->

            </div>
        <!-- /ko -->
    </div>
</script>

<script type="text/html" id="cart.abovePaymentMethods">
    <!-- placeholder -->
</script>
<script type="text/html" id="cart.aboveOrderActions">
    <!-- placeholder -->
</script>

<script type="text/html" id="cart.couponEntry">
    <div id="coupon_entry" class="control-group" data-bind="if: !orderPlaced() && billingSectionValid() && shipmentsSectionsValid()">
        <form class="well">
            <label for="couponcode" class="control-label">
                <b>Have a coupon?</b>
            </label>
            <div class="controls">
                <!-- ko ifnot: couponCode -->
                <div class="input-append">
                    <input type="text" name="couponcode" id="couponcode" class="input-medium" data-bind="value: newCouponCode" placeholder="Enter code">
                    <button class="btn" data-bind="click: function() { SetCouponCode(newCouponCode()); newCouponCode(''); }">Apply</button>
                </div>
                <!-- /ko -->
                <!-- ko if: couponCode -->
                <div class="label label-primary">
                    <strong><span data-bind="text: couponCode"></span></strong> applied.&nbsp;<i style="cursor: pointer" class="icon-remove" title="Remove Coupon" data-bind="click: function() { SetCouponCode(''); }"></i>
                </div>
                <!-- /ko -->
            </div>
        </form>
        <!-- ko template: { name: 'cart.errorList', data: _.filter(errorMessages() , function (error) { return error.errorType == 'coupon'; }) } --><!-- /ko -->
    </div>
</script>


<script type="text/html" id="cart.giftCertificateEntry">
    <div id="giftCertificateEntry" class="control-group" data-bind="if: !orderPlaced() && billingSectionValid() && shipmentsSectionsValid()">
        <form class="well">
            <label for="giftCertCode" class="control-label">
                <b>Have a gift certificate?</b>
            </label>
            <div class="controls">
                <!-- ko ifnot: giftCertCode -->
                <div class="input-append">
                    <input type="text" name="giftCertCode" id="giftCertCode" class="input-medium" data-bind="value: newGiftCertificate" placeholder="Enter code">
                    <button class="btn" data-bind="click: function() { SetGiftCertificate(newGiftCertificate()); newGiftCertificate(''); }">Apply</button>
                </div>
                <!-- /ko -->
                <!-- ko if: giftCertCode -->
                <div class="alert alert-success">
                    <strong><span data-bind="text: giftCertCode"></span></strong> applied.&nbsp;<i style="cursor: pointer" class="icon-remove text-error" title="Remove Gift Certificate" data-bind="click: function() { SetGiftCertificate(''); }"></i>
                </div>
                <!-- /ko -->
            </div>
        </form>
        <!-- ko template: { name: 'cart.errorList', data: _.filter(errorMessages() , function (error) { return error.errorType == 'coupon'; }) } --><!-- /ko -->
    </div>
</script>

<script type="text/html" id="cart.orderActions">

    <div data-bind="visible: !processing() ">
        <div id="restriction_message_container" data-bind="if : $data.restrictionMessages().length > 0">
            <!-- ko template: 'cart.restrictionMessages'--><!-- /ko -->
        </div>
        <div data-bind="visible: orderActions().length > 1" class="order-actions__well">
            <div class="row-fluid order-actions__row">
                <div class="span6 order-actions__span" data-bind="visible: orderActions().length > 1">
                    <div class="order-actions__header" id="order_actions_header">
                        <div class="order-actions__wrapper" data-bind="foreach: orderActions">
                            <label class="radio order-actions__radio">
                                <input type="radio" name="radio" data-bind=" attr: { 'id': $data.refId }, checked: viewModel.selectedOrderActionRefId, value: $data.refID " >
                                <b data-bind=" html: $data.name"></b>
                                <p data-bind=" html: $data.customerDescription"></p>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="span6 order-actions__span">
                    <ul data-bind="foreach: orderActions " class="unstyled">
                        <li data-bind="visible: $data.refID() == (viewModel.selectedOrderAction() && viewModel.selectedOrderActionRefId()) || $parent.orderActions().length == 1">
                            <div id="controlgroup_nickname" class="control-group" data-bind="if: $data.showNickname() || viewModel.nickname()">
                                <label for="nickname" class="control-label">
                                    Name of Order <small class="muted">(optional)</small>
                                </label>
                                <input type="text" class="input-block-level" name="nickname" id="nickname" data-bind="value: viewModel.nickname">
                            </div>
                            <div id="add_comments_container" class="control-group" data-bind="if : ofConfig.allowConversationLogs && $data.showComments">
                                <!-- ko template: 'cart.noteBookComments'--><!-- /ko -->
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
            <!--ko template: { name: 'cart.noteBookNotes', if : viewModel.noteBook().notes().length > 0  } --><!-- /ko -->
        </div>
        <div class="form-actions" id="orderActionButtons" data-bind="foreach: orderActions">
            <!-- ko template: { name: 'cart.termsAndConditions', if: viewModel.showOrderActionButton($data,$parent) } --><!-- /ko -->
            <button
                class="form-actions__place-order btn btn-primary"
                data-bind="
                    html: function() {
                        if($data.showComments() && viewModel.customerComment() != ''  ){
                            return 'Send Comment & ' + $data.buttonLabel();
                        }else{
                            return $data.buttonLabel;
                        }
                    }(),
                    attr: {
                        'id' : $data.refID,
                        'disabled': (
                            (($parent.paymentMethod.paymentType() == 'cc' && $parent.ccn_id() == '') &&
                            (placeOrderActionType() == 'place' || placeOrderActionType() == 'validate')) ||
                            ($data.requireTermsAndConditions() && !$parent.termsAgreement())
                        )
                    },
                    click: viewModel.processOrderAction,
                    visible: viewModel.showOrderActionButton($data,$parent)
            "></button>
        </div>
    </div>
</script>

<script type="text/html" id="cart.termsAndConditions">
    <label for="termsAgreement" class="checkbox terms-agreement" data-bind="visible: ($data.refID() == (viewModel.selectedOrderAction() && viewModel.selectedOrderActionRefId()) || $parent.orderActions().length == 1) && $data.requireTermsAndConditions()">
        <input type="checkbox" class="required" data-bind="checked: $parent.termsAgreement" id="termsAgreement"></input>
        By placing this order, you agree to our <a data-bind="attr: { href: 'page.asp?modal=1&p_key=' + ofConfig.termsAndConditionsPageKey }" class="global-modal" data-title="Terms and Conditions">terms and conditions</a>.  Please check to indicate that you have read them.
    </label>
</script>

<script type="text/html" id="cart.restrictionMessages">
    <div class="well">
        <b>Important Order Information</b>
        <p class="text-warning" data-bind="foreach: restrictionMessages">
            <span data-bind=" html: $data"></span>
        </p>
    </div>
</script>

<script type="text/html" id="cart.checkoutSummary">

    <div id="checkout_summary" class="billing-address-summary__well checkout-summary" data-bind="with: viewModel">

        <!-- ko template: { name: 'cart.couponEntry', if: ofConfig.showCoupon && !ofConfig.showCouponEntryInline } --><!-- /ko -->
        <!-- ko template: { name: 'cart.giftCertificateEntry', if: ofConfig.showGiftCertificate &&  !ofConfig.showGiftCertificateEntryInline } --><!-- /ko -->

        <h3 class="u-checkout-well__title checkout-summary__title">
           Order Summary
        </h3>
        <table class="table checkout-summary__table">
            <tbody>
                <tr data-bind="visible: ofConfig.showEffectiveOrderDate && viewModel.isValidDate(effective_order_date())">
                    <td>Effective Order Date</td>
                    <td id="order_date" class="cell-right" data-bind="text: moment(effective_order_date()).format('MM/DD/YYYY') "></td>
                </tr>
                <tr data-bind="visible: productSubTotalBeforeDiscount() == productTotal()">
                    <td data-bind="html: ofConfig.productSubtotalLabel"></td>
                    <td id="p_total" class="cell-right">
                        <span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(productTotal()) : utils.drawHidePriceMessage()"></span>
                    </td>
                </tr>
                <tr data-bind="visible: productSubTotalBeforeDiscount() != productTotal()">
                    <td data-bind="html: ofConfig.productSubtotalBeforeDiscountLabel"></td>
                    <td id="p_coupon_total" class="cell-right">
                        <span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(productSubTotalBeforeDiscount()) : utils.drawHidePriceMessage()"></span>
                    </td>
                </tr>
                <tr data-bind="visible: productSubTotalBeforeDiscount() != productTotal()">
                    <td><span data-bind="html: ofConfig.productDiscountTotalLabel"></span> (<span data-bind="text: session.TradeAdjustment"></span>%)</td>
                    <td id="p_coupon_total" class="cell-right deduction">
                        <span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(productDiscountTotal()) : utils.drawHidePriceMessage()"></span>
                    </td>
                </tr>
                <tr data-bind="visible: productSubTotalBeforeDiscount() != productTotal()">
                    <td data-bind="html: ofConfig.productSubtotalAfterDiscountLabel"></td>
                    <td id="p_coupon_total" class="cell-right">
                        <span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(productTotal()) : utils.drawHidePriceMessage()"></span>
                    </td>
                </tr>
                <tr data-bind="visible: giftCertCode">
                    <td data-bind="html: ofConfig.giftCertificateTotalLabel"></td>
                    <td id="p_coupon_total" class="cell-right deduction"><span data-bind="html: utils.formatMoney(giftCertAmount())"></span></td>
                </tr>
                <tr data-bind="visible: couponCode">
                    <td data-bind="html: ofConfig.couponSubtotalLabel"></td>
                    <td id="p_coupon_total" class="cell-right deduction"><span data-bind="html: utils.formatMoney(couponDiscountTotals.totalDiscount())"></span></td>
                </tr>
                <tr data-bind="if: ofConfig.bShowShipTotal && ofConfig.bUsingShipping">
                    <td data-bind="html: ofConfig.shippingTotalLabel"></td>
                    <!-- ko if: shipmentsSectionsValid() -->
                    <td id="s_total" class="cell-right">
                        <!-- ko if: ofConfig.showPricingOrderEntry -->
                            <!-- ko if : ofConfig.bShowShipTotalMessage -->
                                <span data-bind="text: ofConfig.sShipTotalText"></span>
                            <!-- /ko -->
                            <!-- ko ifnot: ofConfig.bShowShipTotalMessage -->
                                <!-- ko if: ofConfig.bShowPriceText && shippingTotal() == 0  -->
                                    <span data-bind="text: ofConfig.sShipTotalText"></span>
                                <!-- /ko -->
                                <!-- ko if: !ofConfig.bShowPriceText || shippingTotal() > 0 -->
                                    <span data-bind="html: utils.formatMoney(shippingTotal())"></span>
                                <!-- /ko -->
                            <!-- /ko -->
                        <!-- /ko -->
                        <!-- ko if: !ofConfig.showPricingOrderEntry -->
                            <span data-bind="html: utils.drawHidePriceMessage()"></span>
                        <!-- /ko -->
                    </td>
                    <!-- /ko -->
                    <!-- ko if: !shipmentsSectionsValid() -->
                    <td id="s_total" class="cell-right" >TBD</td>
                    <!-- /ko -->
                </tr>
                <tr data-bind="if: ofConfig.showTaxTotal">
                    <td data-bind="html: ofConfig.taxTotalLabel"></td>
                    <!-- ko if: shipmentsSectionsValid() -->
                        <td id="t_total" class="cell-right"><span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(taxTotal()) : utils.drawHidePriceMessage()"></span></td>
                    <!-- /ko -->
                    <!-- ko if: !shipmentsSectionsValid() -->
                        <td id="t_total" class="cell-right">TBD</td>
                    <!-- /ko -->
                </tr>
                <tr class="success text-large">
                    <td class="text-success"><b><span data-bind="html: ofConfig.orderTotalLabel"></span></b></td>
                    <td class="cell-right text-success">
                        <b><span data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(orderBalance()) : utils.drawHidePriceMessage()"></span></b>
                    </td>
                </tr>
            </tbody>
        </table>
        <!-- ko if : !ofConfig.showOrderActionsInline && !viewModel.completed() -->
            <!-- ko template: { name: 'cart.orderActions', if: shippingComplete() && paymentMethodID() && orderActions().length > 0 } --><!-- /ko -->
            <div data-bind="if: orderActions().length == 0 && shippingComplete() && paymentMethodID()">
                <div class="alert alert-info">There are no actions available at this time.</div>
            </div>
        <!-- /ko -->

    </div>
</script>

<script type="text/html" id="cart.noteBookComments">
    <div class="convolog-comments">
        <div id="external_comments_wrapper" class="convolog-comments__wrapper">
            <label for="external_comments" class="convolog-comments__label">
                Comments <small class="muted">(optional)</small>
            </label>
            <textarea
                id="external_comments"
                class="input-block-level convolog-comments__textarea"
                rows="3"
                autocomplete="off"
                data-bind="textInput: viewModel.customerComment">
            </textarea>
            <!-- This button was confusing users. It's disabled for now, but may be revisited in the future to
                improve the UX. -dnelsen 04/27/2020
            <div class="convolog-comments__btn-wrapper" data-bind="visible: viewModel.customerComment() != ''  ">
                <a class="btn convolog-comments__btn" data-bind="event : { 'click' : viewModel.saveCustomerComment }">Post Comments <i class="icon-arrow-down"></i></a>
            </div>
            -->
            <p class="help-block text-small" data-bind="html: ofConfig.orderCommentHelpText"></p>
        </div>
    </div>
</script>

<script type="text/html" id="cart.noteBookNotes">
    <div id="conversation_log_detail" >
        <div name="conversation_detail_template">
            <h3 class="u-checkout-well__title convolog-comments__title">Comments For This Order</h3>
            <div class="convolog-comments__entries">
                <ul class="list-group convolog-comments__entries-group" data-bind="foreach: $data.noteBook().notes()">
                    <li class="list-group-item convolog-comments__entries-item">
                        <div class="convolog-comments__content">
                            <p class="convolog-comments__entries-text" data-bind="html: $data.externalNotes"></p>
                            <small class="muted convolog-comments__entries-date"><i class="icon-user"></i> <span data-bind="html: $data.postedByName + ' at ' + $data.createDate"></span></small>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.paymentMethodSummary">
    <ul class="unstyled">
        <li><b>Payment</b></li>
        <li data-bind="text: paymentMethod.name"></li>
        <!-- ko if: paymentMethod.paymentType() === 'cc' -->
            <li><strong data-bind="text: vaultedPayment.cardType"></strong> ending in <strong data-bind="text: vaultedPayment.last4"></strong></li>
            <li class="payment-method-summary__expiration">Expires <strong><span data-bind="text: vaultedPayment.expMonth"></span>/<span data-bind="text: vaultedPayment.expYear"></span></strong></li>
        <!-- /ko -->
    </ul>
    <input type="hidden" id="ponumber" data-bind="value: poNumber"/>
</script>

<script type="text/html" id="cart.confirmation">
    <div id="checkout_confirmation" class="checkout-section u-checkout-well" data-bind="visible: viewModel.showConfirmationMessage ">
        <div class="print-hide print-btn__wrapper">
            <!-- ko template: 'cart.continueShoppingButton'--><!-- /ko -->
            <!-- ko template: 'cart.printButton'--><!-- /ko -->
        </div>
        <div class="confirmation-alert__wrapper">
            <!-- ko if: viewModel.selectedLifecycleStage().confirmationMessage() != '' -->
            <div clas="confirmation-alert" data-bind="attr: { 'class': 'confirmation-alert-box ' + selectedLifecycleStage().displayClass() }">
                <i class="icon-2x pull-left"></i>
                <h4 style="margin-top: 4px;" data-bind="html: selectedLifecycleStage().confirmationMessage()"></h4>
            </div>
            <!-- /ko -->
            <!-- ko if: viewModel.selectedLifecycleStage().confirmationMessage() == '' -->
            <div class="confirmation-alert">
                <h3 class="text-success" data-bind="visible: completed"><i class="icon-ok"></i> Thank you for your order!</h3>
                <h3 class="text-success" data-bind="visible: !completed() && viewModel.recordType() == 'recurring' "><i class="icon-save"></i> Recurring Order Saved.</h3>
                <h3 class="text-success" data-bind="visible: !completed() && viewModel.lifecycleStage() == 'pending' "><i class="icon-refresh"></i> This order is pending approval.</h3>
                <h3 class="text-success" data-bind="visible: !completed() && viewModel.lifecycleStage() != 'pending' && viewModel.lifecycleStage() != 'recurring' && viewModel.lifecycleStage() != 'cancelled' "><i class="icon-save"></i> This order has been saved.</h3>
                <h3 class="text-error" data-bind="visible: viewModel.lifecycleStage() == 'cancelled' "><i class="icon-remove"></i> This order was rejected.</h3>
            </div>
            <!-- /ko -->
        </div>

        <div class="checkout-section-body">

            <div class="order-number checkout-section-inner well">

                <!-- ko if: completed() && orderNumber() -->
                <h3>Your order number is&nbsp;<span data-bind="text: ofConfig.orderNumberPrefix"></span><span data-bind="text: orderNumber"></span></h3>
                <!-- /ko -->
                <div class="row-fluid checkout-section__row">

                    <div class="span3 checkout-section__span">
                        <!-- ko template: 'cart.paymentMethodSummary' --><!-- /ko -->
                    </div>

                    <div class="span3 checkout-section__span">
                        <div id="controlgroup_invoice_ponumber_summary" class="control-group checkout-section__summary-wrapper" data-bind="if: poNumber">
                            <div class="checkout-section__summary">
                                <b for="ponumber_summary" class="po-label" data-bind="html: ofConfig.POLabel"></b>
                                <div class="controls">
                                    <span id="ponumber_summary" class="" data-bind="text: poNumber"></span>
                                </div>
                            </div>
                        </div>
                        <div id="controlgroup_invoice_comments_summary" class="control-group checkout-section__summary-wrapper" data-bind="if: comments">
                            <div class="checkout-section__summary">
                                <label for="order_comments_summary" class="control-label">
                                    <strong data-bind="text: ofConfig.fulfillmentCommentsText"></strong>
                                </label>
                                <div class="controls">
                                    <div id="order_comments_summary" data-bind="text: comments"></div>
                                </div>
                            </div>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.errorList">
    <div id="errorList">
        <!-- ko if: $data.length > 0 && !viewModel.completed() -->
            <div  class="alert alert-error">
                <span class="error-list__wrapper" data-bind="foreach: $data">
                    <strong class="error-list__message" data-bind="text: message"></strong>
                </span>
            </div>
        <!-- /ko -->
    </div>
</script>

<script type="text/html" id="cart.allocationNotComleteMessage">
    <div class="alert alert-warning">
        <h3 class="text-warning"><i class="icon-warning-sign"></i> Your shipments aren't complete.</h3>
        <p>All products on your order must be allocated to shipments before you can complete the order.</p>
    </div>
</script>

<!-- bound -->
<script type="text/html" id="cart.billingForm">
    <!-- ko if: showBillingEdit -->
    <div id="billing_address_form" class="form-horizontal">
        <!-- ko template: { name: 'cart.orderContact', data: viewModel.customer } --> <!-- /ko -->
        <!-- ko template: { name: 'cart.billingAddress', data: viewModel.account } --> <!-- /ko -->
    </div>
    <!-- /ko -->
</script>

<!-- bound -->
<script type="text/html" id="cart.orderContact">
    <fieldset>
        <legend>Contact Information</legend>
        <div class="control-group" data-bind="validationElement: $data.firstName">
            <label for="bill_f_nm" class="control-label">First Name</label>
            <div class="controls">
                <input type="text" id="bill_f_nm" data-bind="value: $data.firstName">
            </div>
        </div>

        <div class="control-group" data-bind="validationElement: $data.lastName">
            <label for="bill_l_nm" class="control-label">Last Name</label>
            <div class="controls">
                <input type="text" id="bill_l_nm" data-bind="value: $data.lastName">
            </div>
        </div>

        <div class="control-group" data-bind="validationElement: $data.email">
            <label for="bill_em" class="control-label">Email</label>
            <div class="controls">
                <input type="text" id="bill_em" data-bind="value: $data.lastName">
            </div>
        </div>

        <div class="control-group" data-bind="validationElement: $data.phone">
            <label for="bill_phone" class="control-label">Phone</label>
            <div class="controls">
                <input type="text" id="bill_phone" data-bind="value: $data.phone">
                <div class="help-inline text-small">Format: <span id="gc-number-1" class="gc-cs-link" title="Call with Google Voice">888-555-1234</span> xxxx</div>
            </div>
        </div>
    </fieldset>
</script>

<script type="text/html" id="cart.billingAddress">
    <fieldset>
        <legend>Billing Address</legend>
        <!-- ko template: { name: 'cart.addressInfo' } --><!-- /ko -->
    </fieldset>
</script>

<!-- bound -->
<script type="text/html" id="cart.billingSummary">
    <!-- ko ifnot: showBillingEdit -->
          <div id="billing_address_summary" class="row-fluid billing-address-summary__row">
                <div class="billing-address-summary__well">
                <b>Contact Information</b>
                <button
                    type="button"
                    id="contact-address"
                    class="btn btn-link btn-mini global-modal billing-address-summary__edit-button"
                    data-bind="
                        attr: { 'href': 'account.asp?modalaction=editcontact&modal=1&o_key=' + viewModel.orderKey() },
                        visible: viewModel.allowContactEdits(),
                        addModalHandler: { 'element' : $('#contact-address'), 'handler' : function() { location.reload() }}"
                    data-title="Edit Contact Information"
                    data-size="large"
                >
                    <small>Edit</small>
                </button>
                <!-- ko template: { name: 'cart.orderContactSummary', data: customer } --> <!-- /ko -->
                </div>

                <!-- ko if: completed() -->
                <div class="billing-address-summary__well">
                    <!-- ko template: {
                        name: 'cart.shippingSummary',
                        data: shipments(),
                        if : (viewModel.shippingComplete() ||  viewModel.completed()) && shipments().length > 0 } -->
                    <!-- /ko -->
                </div>
                <!-- /ko -->

                <div class="billing-address-summary__well">
                    <b>Billing Address</b>
                    <button
                        type="button"
                        id="billing-address"
                        class="btn btn-link btn-mini global-modal billing-address-summary__edit-button"
                        data-bind="
                            attr: { 'href': 'account.asp?modalaction=editaccount&modal=1&o_key=' + viewModel.orderKey() },
                            visible: viewModel.allowAccountEdits(),
                            addModalHandler: { 'element' : $('#billing-address'), 'handler' : function() { location.reload() } }"
                        data-title="Edit Billing Information"
                        data-size="large"
                    >
                        <small>Edit</small>
                    </button>
                        <!-- ko template: { name: 'cart.billingAddressSummary', data: billToAccount } --><!-- /ko -->
                </div>

                <span class="checkout-summary__order-total -hidden-mobile">
                    <!-- ko template: { name: 'cart.checkoutSummary' } --><!-- /ko -->
                </span>
              </div>
    <!-- /ko -->
</script>

<!-- bound -->
<script type="text/html" id="cart.orderContactSummary">
    <ul class="unstyled">
        <li><span data-bind="text: $data.firstName"></span> <span data-bind="text: $data.lastName"></span></li>
        <li data-bind="text: $data.email"></li>
        <li data-bind="text: $data.phone"></li>
    </ul>
</script>

<!-- bound -->
<script type="text/html" id="cart.billingAddressSummary">
    <ul class="unstyled">
        <li data-bind="text: $data.company"></li>
        <li data-bind="text: $data.address1, visible: !!$data.address1()"></li>
        <li data-bind="text: $data.address2, visible: !!$data.address2()"></li>
        <li data-bind="text: $data.address3, visible: !!$data.address3()"></li>
        <li data-bind="text: $data.address4, visible: !!$data.address4()"></li>
        <li data-bind="text: $data.address5, visible: !!$data.address5()"></li>
        <li data-bind="visible: $data.city || $data.state || $data.zipCode"><span data-bind="text: $data.city"></span><span data-bind="visible: $data.city"
        >, </span><span data-bind="text: $data.state"></span> <span data-bind="text: $data.zipCode"></span></li>
        <li data-bind="text: $data.country, visible: $data.country"></li>
    </ul>
</script>

<script type="text/html" id="cart.shipmentMethodSelector">
    <div class="radiogroup" data-bind="foreach: shipViaChoices">
        <!-- ko if: eligible -->
            <label class="radio clearfix" data-bind="attr: { for: $parentContext.$index() + 'single_sm_0' + $context.$index() }, css: { active: $parent.selectedShipVia.shipViaChoiceID() == shipViaChoiceKey() }">
                <input class="ship-via-radio" type="radio" data-bind="attr: { disabled: viewModel.orderPlaced, name: $parentContext.$index() + 'single_sm_0' + $context.$index(), id: $parentContext.$index() + 'single_sm_0' + $context.$index() }, checked: $parent.selectedShipViaChoice, value: $data"><span data-bind="html: name"></span>
                <!-- ko if: ofConfig.bShowShipViaPrice && ofConfig.showPricingOrderEntry -->
                    <span class="sv-price pull-right" data-bind="ifnot: viewModel.superUserOrderFormMode() && ofConfig.superUserAllowShippingPriceEdits">
                        <!-- ko if : ofConfig.bShowShipTotalMessage -->
                            <span data-bind="text: ofConfig.sShipTotalText"></span>
                        <!-- /ko -->
                        <!-- ko ifnot: ofConfig.bShowShipTotalMessage -->
                            <!-- ko if: ofConfig.bShowPriceText && total() == 0  -->
                                <span data-bind="text: ofConfig.sShipTotalText"></span>
                            <!-- /ko -->
                            <!-- ko if: !ofConfig.bShowPriceText || total() > 0 -->
                                <span data-bind="html: utils.formatMoney(total())"></span>
                            <!-- /ko -->
                        <!-- /ko -->
                    </span>
                    <div class="su-sv-inputs pull-right" data-bind="if: viewModel.superUserOrderFormMode() && ofConfig.superUserAllowShippingPriceEdits">
                        <button type="button" class="btn btn-mini btn-link su-price-reset" data-bind="visible: priceCalcType() == 'fixed',event: { click: viewModel.resetSuperUserShippingPrice } ">
                            <span data-bind="html: ofConfig.superUserResetPriceHelpText"></span>
                        </button>
                        <div class="input-prepend">
                            <span class="add-on">$</span>
                            <input type="text" class="text-right" data-bind="value: total().toFixed(2), event: { change: viewModel.superUserSetShipViaPrice }">
                        </div>
                        <span class="orig-price" data-bind="visible: false && priceCalcType() == 'fixed', html: '( ' + utils.formatMoney(rate()) + ' )'"></span>
                    </div>
                <!-- /ko -->
                <!-- ko if: !ofConfig.showPricingOrderEntry -->
                <div class="sv-hidden-price pull-right" data-bind="html: ofConfig.sShipTotalText"></div>
                <!-- /ko -->
            </label>
        <!-- /ko -->
    </div>
    <!-- ko if: shipViaChoices().length == 0 || !(shipViaChoices().find(function(item) { return item.eligible() })) -->
        <span class="alert alert-error">No Shipping Methods Available</span>
    <!-- /ko -->
    <!-- ko if: ofConfig.ShowShipViaDS && selectedShipVia.description -->
        <div id="shipping-ds0" class="alert alert-info alert-block without-close shipping-ds" data-bind="html: selectedShipVia.description">
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipperAccountSelector">
    <!-- ko if: selectedShipVia.collectShippingAccount() -->
        <div class="alert alert-info alert-block without-close shipping-account-info"
             data-bind="attr: { 'id' : 'shipping-account-info' + parseInt($context.$index() + 1) }">
            <div data-bind="attr: { 'id' : 'sv-collect-info-msg' + parseInt($context.$index() + 1) }">
                <h4>Select or add a shipping account</h4>
                <p>This shipping method requires that you provide your own shipper account number to cover the shipping charges.</p>
            </div>
            <div class="input-append shipping-account-select" data-bind="attr: { 'id' : 'shipping-account-select' + parseInt($context.$index() + 1) }, validationOptions: { messageTemplate: null, insertMessages: false }">

                <select class="selShipAcct" style="width: auto;" data-bind="
                    attr: {
                        'id' : 'selShipAcct' + parseInt($context.$index() + 1),
                        'name' : 'selShipAcct' + parseInt($context.$index() + 1)
                    },
                    options: selectedShipVia.shippingAccounts,
                    optionsText:
                        function(item){
                            if( ko.unwrap(item.name) != ''){
                                return  ko.unwrap(item.name) + ' (' + ko.unwrap(item.number) + ')';
                            }else{
                                return ko.unwrap(item.carrier) + ' (' + ko.unwrap(item.number) + ')';
                            }
                        },
                    value: selectedShipVia.shippingAccountId,
                    optionsValue: 'shippingAccountKey',
                    optionsCaption: 'Select an account...'
                "></select>
                <!-- ko if: ofConfig.superUserAllowShipperAccountEdits && selectedShipVia.shippingAccounts().length > 0 && selectedShipVia.shippingAccountId() != undefined -->
                    <a id="btnEditShipAcct1"
                        data-selshipacct_id="selShipAcct1"
                        class="btn btnEditShipAcct global-modal"
                        data-bind="
                            html: ofConfig.sShipAccountEditButtonText,
                            attr: {
                                href : 'sf_shipping_account_ae.asp?modal=1&key=' + selectedShipVia.shippingAccountId()
                            },
                            addModalHandler: { 'element' : $('.btnEditShipAcct.global-modal'), 'handler' : viewModel.genericModalComplete }
                        "></a>
                <!-- /ko -->
                <!-- ko if : ofConfig.superUserAllowShipperAccountAdds -->
                <a class="btn btnAddShipAcct global-modal"
                href="sf_shipping_account_ae.asp?modal=1"
                data-bind="
                        html : ofConfig.sShipAccountAddbuttonText,
                        addModalHandler: { 'element' : $('.btnAddShipAcct.global-modal'), 'handler' : viewModel.genericModalComplete },
                        attr : {
                            id : 'btnAddShipAcct' + parseInt($context.$index() + 1
                        }
                    "></a>
                <!-- /ko -->
            </div>
            <div data-bind="if: !selectedShipVia.shippingAccountId.isValid() && selectedShipVia.shippingAccounts().length > 0">
                <p class="alert alert-error">Please select or add a shipping account</p>
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentGiftOptions">
    <div class="control-group">
        <label for="gift_msg" class="control-label" data-bind=" html : ofConfig.sShipmentCommentLabel"></label>
        <div class="controls">
            <div class="text-small gift-msg-help">
                <span data-bind=" html : ofConfig.sShipmentCommentHelpText"></span>
            </div>
            <textarea class="gift_msg__textarea" rows="3" maxlength="250" autocomplete="off" data-bind="value: comments, attr: { readonly: viewModel.orderPlaced }"></textarea>
            <span class="help-block text-small">Up to 250 characters</span>
        </div>
    </div>
</script>

<script type="text/html" id="cart.shipmentGiftOptionsSummary">


</script>

<script type="text/html" id="cart.productLeadTimes">
    <!-- ko if: ofConfig.bShowProductLeadTimes && ofConfig.productLeadTimesText != '' && leadTimeDays() > 0 -->
        <div
            class="text-small text-info"
            style="margin-bottom: 5px;"
            data-bind="html: ofConfig.productLeadTimesText.replace('<days>', leadTimeDays() )"
        >
        </div>
    <!-- /ko -->
</script>


<script type="text/html" id="cart.expectedShipDate">
    <span data-bind="visible: ofConfig.showExpectedShipDate && !ofConfig.UseRequestedDay, html: ofConfig.expectedShipDate.replace('<date>', moment(expectedShipDate()).format('MM/DD/YYYY') )"></span>
</script>

<!-- bound -->
<script type="text/html" id="cart.requestedShipDate">
    <div class="control-group"
            data-bind="visible: selectedShipVia">
        <label class="control-label" data-bind="html: ofConfig.requestedShipDateLabel"></label>
        <div class="controls">
        <!-- ko if: viewModel.orderPlaced -->
            <span class="requested-date" data-bind="text: requestedShipDate"></span>
        <!-- /ko -->
        <!-- ko ifnot: viewModel.orderPlaced -->
            <div class="input-append">
                <input type="text" class="input-medium"
                    style="background-color: white;cursor: pointer"
                    readonly="readonly"
                    data-bind="attr: { disabled: viewModel.orderPlaced, id: selectedShipVia.shipViaChoiceID }
                        , datepicker: requestedShipDate
                        , datepickerOptions: {
                            minDate: new Date(earliestShipDate()),
                            maxDate: moment(new Date()).add(ofConfig.shipCutoffNumDaysOut, 'days').toDate(), 
                            constrainInput: true,
                            showOn:'both',
                            buttonText: '<i class=\'icon-calendar\'></i>',
                            beforeShowDay: function (date) {
                                return [isValidRequestedDate(date)];
                            }
                        }">
            </div>
        <!-- /ko -->
        </div>
    </div>
</script>

<script type="text/html" id="cart.requestedShipDateSummary">
    <div class="control-group">
        <label class="control-label">Ship On</label>
        <div class="controls">
            <div class="uneditable-text" data-bind="text: requestedShipDate"></div>
        </div>
    </div>
</script>


<!-- bound -->
<script type="text/html" id="cart.addressInfo">
    <div class="control-group" data-bind="validationElement: $data.company">
        <label for="s_company" class="control-label">Name/Company</label>
        <div class="controls">
            <input type="text" id="s_company" class="input-xlarge" data-bind="value: $data.company">
            <span class="help-inline text-small">(optional)</span>
        </div>
    </div>
    <div class="control-group" data-bind="validationElement: $data.address1">
        <label for="s_add1" class="control-label">Street Address</label>
        <div class="controls">
            <input type="text" id="s_add1" class="input-xlarge" data-bind="value: $data.address1">
        </div>
    </div>
    <div class="control-group" data-bind="validationElement: $data.address2">
        <label for="s_add2" class="control-label">Address 2</label>
        <div class="controls">
            <input type="text" id="s_add2" data-bind="value: $data.address2">
            <span class="help-inline text-small">(optional)</span>
            <div class="help-block text-small">Apartment, Suite, Building, Floor, etc.</div>
        </div>
    </div>
    <div class="control-group" data-bind="validationElement: $data.country">
        <label for="s_country" class="control-label">Country</label>
        <div class="controls">
            <select id="s_country" data-bind="value: $data.country, options: countries, optionsText: 'countryName', optionsValue: 'iso3', optionsCaption: 'Select a country...', change: $data.loadStates">
            </select>
        </div>
    </div>
    <div class="control-group" data-bind="validationElement: $data.city">
        <label for="s_city" class="control-label">City</label>
        <div class="controls">
            <input type="text" id="s_city" data-bind="value: $data.city">
        </div>
    </div>
    <div class="control-group" data-bind="validationElement: $data.state">
        <label for="s_state" class="control-label">State / Province</label>
        <div class="controls">
            <select id="s_state" data-bind="value: $data.state, options: $data.stateChoices, optionsText: 'name', optionsValue: 'code', optionsCaption: 'Select a state...'">
            </select>
        </div>
    </div>
    <!-- div class="control-group" data-bind="validationElement: $data.County">
        <label for="s_county" class="control-label">County</label>
        <div class="controls">
            <input type="text" id="s_county" data-bind="value: $data.County">
        </div>
    </div -->
    <div class="control-group" data-bind="validationElement: $data.zipCode">
        <label for="s_zip" class="control-label">ZIP / Postal Code</label>
        <div class="controls">
            <input type="text" id="s_zip" class="input-small" data-bind="value: $data.zipCode">
        </div>
    </div>
    <div class="control-group" data-bind="visible: $data.hasOwnProperty('phone')">
        <label for="s_phone" class="control-label">Phone</label>
        <div class="controls">
            <input type="text" id="s_phone" data-bind="value: $data.phone">
            <div class="help-block text-small">Format: <span id="gc-number-2" class="gc-cs-link" title="Call with Google Voice">888-555-1234</span> xxxx</div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.shippingSummary">
    <!-- ko if: $data.length > 0 -->
        <div class="checkout-section-inner">
            <span data-bind="visible : viewModel.useMultiShipEditUI">Your order is being shipped to multiple locations.</span>
            <!-- ko ifnot : viewModel.useMultiShipEditUI -->
                <!-- ko template : { name: 'cart.addressSummaryInfo', data: $data[0].shipTo }--><!-- /ko-->
            <!-- /ko -->
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.addressSummaryInfo">
    <b>Shipping Address </b>
    <div data-bind=" forEach: $data " class="address-summary">
        <!-- ko if: attention -->
            <div data-bind="text: attention() + ', '"></div>
        <!-- /ko -->
        <!-- ko if: company -->
            <div data-bind="text: company()"></div>
        <!-- /ko -->
        <!-- ko if: firstName() || lastName() -->
            <div data-bind="text: firstName() + ' ' + lastName() + ', '"></div>
        <!-- /ko -->
        <div data-bind="text: address1, visible: address1"></div>
        <div data-bind="text: address2, visible: address2"></div>
        <div data-bind="text: address3, visible: address3"></div>
        <div data-bind="text: address4, visible: address4"></div>
        <div data-bind="text: address5, visible: address5"></div>
        <div data-bind="visible: city || state || zipCode">
            <span data-bind="text: city"></span><span data-bind="visible: city">, </span><span data-bind="text: state"></span> <span data-bind="text: zipCode"></span>
        </div>
        <span data-bind="text: country; visible: country"></span>
        <span data-bind="template: { name: 'cart.addressOptFields', foreach: getAddressOptFields() }"></span>
    </div>
</script>

<script type="text/html" id="cart.addressOptFields">
    <div data-bind="text: ofConfig['addressOpt'+$data+'Label'] + ': ' + $parent['opt'+$data]()"></div>
</script>

<script type="text/html" id="cart.shipmentItemListSummary">
    <!-- ko if: details().length > 0 -->
        <!-- ko foreach: details -->
            <div class="checkout-multiship-item media">
                <img
                    data-bind="attr : { alt: orderDetail.sku() + ' - ' + orderDetail.name(),
                            src: utils.buildImagePath(orderDetail.thumbnail()) }"
                    class="media-object"
                    onerror="utils.handleImageError(this)">
                <div class="media-heading">
                    <span data-bind="text: orderDetail.sku"></span> - <span data-bind="html: orderDetail.name"></span>
                    <!-- ko template: { name :'cart.productLeadTimes', data: orderDetail} --><!-- /ko -->
                </div>
                <small>Qty: <span data-bind="text: qtyToShip"></span> of <span data-bind="text: orderDetail.qty"></span>
                    <!-- ko if:ofConfig.showUom -->
                    &nbsp;<span class="uom" data-bind="text: orderDetail.uom"></span>
                    <!-- /ko -->
                </small>
            </div>
        <!-- /ko -->
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentItemList">
     <!-- ko if: details().length > 0 -->
        <div data-bind="foreach: details">
            <div class="media">
                <img
                    data-bind="visible: !oConfig.fastTrack, attr : { alt: orderDetail.sku() + ' - ' + orderDetail.name(),
                            src: utils.buildImagePath(orderDetail.thumbnail()) }"
                    class="media-object pull-left cart-item-pic"
                    onerror="utils.handleImageError(this)">
                <div class="media-body">
                    <!-- <div class="cart-item-sku" data-bind="text: orderDetail.sku"></div> -->
                    <p class="cart-item-name">
                        <span data-bind="html: orderDetail.name"></span>
                        <!-- ko template: { name: 'cart.backorderMessage', data: orderDetail, if: ofConfig.showBackorderMessage } --><!-- /ko -->
                        <!-- ko template: { name :'cart.productLeadTimes', data: orderDetail} --><!-- /ko -->
                        <!-- ko template: { name: 'cart.softgoods', data: orderDetail, if: ofConfig.showSoftGoodAuthorizations } --><!-- /ko -->
                        <!-- ko if: orderDetail.promoID -->
                            <span class="promo-icon" data-bind="attr: { 'title' : orderDetail.promoDescription() } ">P</span>
                        <!-- /ko -->
                    </p>
                    <p><span data-bind="html: orderDetail.instanceUnitPriceDisplay()"></span></p>
                    <div class="cart-item-total-qty">
                        <span class="badge" data-bind="text: qtyToShip()"></span>
                        &nbsp;
                        <!-- ko if:ofConfig.showUom -->
                        <span class="uom" data-bind="text: orderDetail.uom"></span>
                        <!-- /ko -->
                        <span data-bind="html: 'On ' + ofConfig.SavedCartLabel"></span>
                    </div>
                </div>
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentItemTable">
    <!-- ko if: details().length > 0 && !viewModel.isOverLineLimit() -->
        <!-- ko template: { afterRender: function() { $(document).trigger('enhance.tablesaw'); } } -->
            <table class="tablesaw cart-table" data-tablesaw-mode="stack" role="presentation">
                <thead>
                    <th class="cart-desc__th" data-bind="text: ofConfig.labels.cartDesc"></th>
                    <th class="cart-qty__th" data-bind="text: ofConfig.labels.cartQty"></th>
                    <!-- ko if: ofConfig.showPricingOrderEntry -->
                    <th class="cart-price__th" data-bind="text: ofConfig.labels.cartItemPrice"></th>
                    <!-- /ko -->
                    <!-- ko if: ofConfig.showPricingOrderEntry -->
                    <th class="cart-total__th" data-bind="text: ofConfig.labels.cartTotal"></th>
                    <!-- /ko -->
                    <!-- ko if: ofConfig.allowProductEditInFinalStep && viewModel.recordType() != 'recurring' --><!-- /ko -->
                </thead>
                <tbody class="cart-row-std" data-bind="foreach: details">
                    <!-- ko if: orderDetail.parentProductID().trim() == '' || !orderDetail.hasParentInCart() -->
                    <tr>
                        <td>
                            <div class="media">
                                <img
                                    data-bind="visible: !oConfig.fastTrack,
                                            attr : { alt: orderDetail.sku() + ' - ' + orderDetail.name(),
                                            src: utils.buildImagePath(orderDetail.thumbnail()) },
                                            css: { 'print-hide': !ofConfig.showProductImagesWhenPrinting }"
                                    class="media-object pull-left cart-item-pic"
                                    onerror="utils.handleImageError(this)">
                                <div class="media-body">
                                    <div class="cart-item-sku" data-bind="text: orderDetail.sku, visible: !orderDetail.parentProductID().trim() || !orderDetail.hasParentInCart()"></div>
                                    <div class="cart-item-name" >
                                        <span data-bind="html: orderDetail.name"></span>
                                        <!-- ko template: { name: 'cart.backorderMessage', data: orderDetail, if: ofConfig.showBackorderMessage } --><!-- /ko -->
                                        <!-- ko template: { name :'cart.productLeadTimes', data: orderDetail} --><!-- /ko -->
                                        <!-- ko template: { name: 'cart.softgoods', data: orderDetail, if: ofConfig.showSoftGoodAuthorizations } --><!-- /ko -->
                                        <!-- ko if: viewModel.recordType() === 'recurring' -->
                                            <div class="recurring-summary" data-bind="html: viewModel.getRecurringLabel($data)"></div>
                                        <!-- /ko -->
                                        <!-- ko if: orderDetail.promoID -->
                                            <span class="promo-icon" data-bind="attr: { 'title' : orderDetail.promoDescription() } ">P</span>
                                        <!-- /ko -->
                                    </div>
                                    <p data-bind="if: ofConfig.AllowWarehouse && orderDetail.productWarehouse">
                                        <span data-bind="html: ofConfig.warehouseLabel + ' ' + orderDetail.productWarehouse.name()"></span>
                                    </p>
                                    <!-- ko if : ofConfig.bShowCartOptions && orderDetail.cartOption -->
                                        <p data-bind="text: orderDetail.cartOption"></p>
                                    <!-- /ko -->
                                    <!-- ko template: { name: "cart.additionalDetailLineInfo", data: orderDetail } --><!-- /ko -->
                                </div>
                            </div>
                        </td>
                        <td class="instance-qty-ship__td">
                            <span data-bind="text: qtyToShip"></span><span data-bind="if: ofConfig.showTotalQtyOnShipment"> of <span data-bind="text: orderDetail.qty"></span></span>
                            <!-- ko if:ofConfig.showUom -->
                            &nbsp;<span class="uom" data-bind="text: orderDetail.uom"></span>
                            <!-- /ko -->
                        </td>
                        <!-- ko if: ofConfig.showPricingOrderEntry -->
                        <td class="instance-unit-price__td">
                            <span data-bind="html: orderDetail.instanceUnitPriceDisplay()"></span>
                        </td>
                        <td class="instance-ext-price__td">
                            <span data-bind="html: utils.formatMoney(orderDetail.instanceExtPrice())"></span>
                        </td>
                        <!-- /ko -->

                        <!-- ko if: !ofConfig.showPricingOrderEntry -->
                        <td class="instance-hidden-price__td" data-bind="html: utils.drawHidePriceMessage()"></td>
                        <!-- /ko -->

                            <!-- ko if: ofConfig.allowProductEditInFinalStep && viewModel.recordType() != 'recurring' -->
                            <td class="recurring__td">
                                <!-- ko template: { name: 'cart.productInlineEditLinks', data: orderDetail } --><!-- /ko -->
                            </td>
                            <!-- /ko -->
                        </tr>


                        <tr class="cart-row-std__config-row -no-border-top" data-bind="if: orderDetail.configuratorJson.choices">
                            <td class="cart-row-std__config-col" colspan="5">
                                <!-- ko template: { name: "cart.configOptions", data: orderDetail } --><!-- /ko -->
                            </td>
                        </tr>


                        <!-- ko if:orderDetail.editing() && viewModel.mainProduct() -->
                        <tr>
                            <td colspan="5">
                                <div class="detail-child-selector">
                                    <span data-bind="template: { name: 'catalog.child_selectors', if: viewModel.mainProduct().childSelectors, data: viewModel.mainProduct().childSelectors }"></span>
                                </div>
                                <!-- ko template: { name:'catalog.atc_full', data:viewModel.mainProduct().selectedProduct, if:viewModel.mainProduct } --><!-- /ko -->
                            </td>
                        </tr>
                        <!-- /ko -->
                    <!-- /ko -->
                </tbody>
            </table>
        <!-- /ko -->
    <!-- /ko -->
    <!-- ko if: viewModel.isOverLineLimit() -->
        <div class="well cart-table" data-bind="html: ofConfig.tooManyLinesMessage"></div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.additionalDetailLineInfo">
</script>

<script type="text/html" id="cart.configOptions">
    <!-- ko if : configuratorJson.choices -->
        <div class="config-options">
            <div class="config-options__title">
                <button class="config-options__toggle"
                        data-bind="click:
                            function(e) {
                                $('.config-options__content').slideToggle();
                                $('.config-options').toggleClass('-closed');
                            }">
                    <span class="config-options__type" style="font-weight: bold;" data-bind="text: configuratorJson.configType() === 'cartoptions' ? 'Options' : 'Configuration Options'"></span>
                    &nbsp;<i class="fas fa-angle-down"></i>
                </button>
                <span class="config-options__details" data-bind="visible: configuratorJson.configType() !== 'cartoptions'">
                    <!-- ko template: { name: 'cart.productEditLink', data: { title: 'Edit Configuration', linkText: '<small>Edit</small>', detailLine: $data } } --><!-- /ko -->
                    <!-- ko template: { name: 'cart.instanceCloneLink', data: { detailLine: $data }, visible: oConfig.showCloneInstanceLink } --><!-- /ko -->
                </span>
            </div>
            <div class="config-options__content">
                <ul class="config-options__group" data-bind="foreach: configuratorJson.choices">
                    <li class="config-options__item"><strong><span data-bind="text: questionText"></span></strong> <span data-bind="text: answerText"></span></li>
                </ul>
                <!-- ko if: instanceChildren.length > 0 -->
                <table class="tablesaw cart-table config-options__cart-table" role="presentation">
                    <thead class="config-options__thead">
                        <th class="config-options__qty-title">Qty</th>
                        <th class="config-options__price-title">Product Price</th>
                        <th class="config-options__desc-title">Description</th>
                    </thead>
                    <tbody class="cart-row-std config-options__tbody" data-bind="foreach: instanceChildren">
                        <tr>
                            <td class="config-options__qty-text" data-bind="text: qty"></td>
                            <td class="config-options__price-text"><span data-bind="html: utils.formatMoney( (priceBeforeAdjustment() || price()) )"></span></td>
                            <td class="config-options__desc-text" data-bind="html: name"></td>
                        </tr>
                    </tbody>
                </table>
                <!-- /ko -->
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.addAddressButton">
    <a
        type="button"
        class="global-modal btn btn-default"
        data-size="full"
        data-title="Add Shipping Address"
        data-bind="
            visible: ofConfig.bAllowShipToAdds,
            attr: { 'href' : 'account.asp?modalaction=addshipto&modal=1&o_key=' + viewModel.orderKey() },
            addModalHandler: { 'element' : $('#shipping_address_summary .global-modal'), 'handler' : addAddressHandler }">
            <i class="icon-plus icon-fixed-width"></i>Add Address
    </a>
</script>

<script type="text/html" id="cart.addProductButton">

    <div class="form-buttons input-append">
        <label>Find a Product</label>
        <div class="add-product-actions" >
            <a
                class="btn global-modal add-product-actions__bulk"
                data-size="full"
                data-title="Add Products"
                onclick="$('#handle-modal-exit').val(true)"
                data-bind="
                    attr: {
                        'href' : 'queue_atc.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey()
                    },
                    visible: ofConfig.showBulkAdd
                "
            >Bulk Add</a>
            <a
                class="btn global-modal add-product-actions__browse"
                data-size="full"
                data-title="Add Products"
                onclick="$('#handle-modal-exit').val(true)"
                data-bind="
                    attr: { 'href' : 'pc_combined_results.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey() }"
            >Browse/Search</a>
            <a
                class="btn global-modal add-product-actions__from-fave"
                data-size="full"
                data-title="Add Products"
                onclick="$('#handle-modal-exit').val(true)"
                data-bind="
                    attr: { 'href' : 'favorites_lists.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey() }"
            >From Favorites</a>
            <a
                class="btn global-modal add-product-actions__from-so"
                data-size="full"
                data-title="Add Products"
                onclick="$('#handle-modal-exit').val(true)"
                data-bind = "
                    attr: { 'href' : 'sales_orders.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey()}"
            >From Sales Order</a>
            <a
                class="btn global-modal add-product-actions__from-inv"
                data-size="full"
                data-title="Add Products"
                onclick="$('#handle-modal-exit').val(true)"
                data-bind = "
                    attr: { 'href' : 'invoices.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey()}"
            >From Invoice</a>
        </div>
    </div>
</script>

<style type="text/css">
    .media.noborder, .tablesaw-stack tbody tr.noborder, .item-list .media.noborder {
        border-bottom:0;
        margin-bottom:0;
        padding-bottom:0;
        border-top: 0;
        display: none;
    }

    .tablesaw tbody tr, .item-list .media  {
        border-top: 1px solid #dfdfdf;
        border-bottom: 0;
    }
    .item-list .media {
        padding-top: 10px;
    }

    .configOptions {
        list-style-type: none;
        margin-right: 10px;
    }
</style>

<script type="text/html" id="cart.itemCard">

        <tr class="item-card">

            <td class="item-card__cart-item">
                <b class="tablesaw-cell-label">Description</b>
                <figure class="item-card__cart-item-img" data-bind="visible: !oConfig.fastTrack && parentProductID().trim() && hasParentInCart()"></figure>
                <figure class="item-card__prod-info-wrapper">
                    <img data-bind="attr : { alt: sku() + ' - ' + name(),
                                    src: utils.buildImagePath(commodity.pic.thumb()) },
                                    visible: !oConfig.fastTrack && (!parentProductID().trim() || !hasParentInCart() )"
                        class="item-card__prod-info-img"
                        onerror="utils.handleImageError(this)">

                    <figcaption class="item-card__prod-text-wrapper">
                        <b class="item-card__prod-name" data-bind="html: name"></b>

                        <!-- ko if : promoID -->
                        <span class="item-card__promo-icon promo-icon" data-bind="attr: { 'title' : promoDescription() } ">P</span>
                        <!-- /ko -->

                        <div class="item-card__prod-sku text-xsmall muted" data-bind="text: sku, visible: !parentProductID().trim() || !hasParentInCart()"></div>

                        <p data-bind="if: ofConfig.AllowWarehouse && productWarehouse">
                            <span data-bind="html: ofConfig.warehouseLabel + ' ' + productWarehouse.name()"></span>
                            <span data-bind="if: viewModel.allowWarehouseSelection() && !viewModel.useMultiShipEditUI()">
                                <!-- ko template: { name: 'cart.productEditLink', data: { title: 'Change Warehouse', linkText: 'Change Warehouse', detailLine: $data } } --><!-- /ko -->
                            </span>
                        </p>
                        <!-- ko template: { name: 'cart.backorderMessage', if: ofConfig.showBackorderMessage } --><!-- /ko -->
                        <!-- ko template: 'cart.productLeadTimes' --><!-- /ko -->
                        <!-- ko template: { name: 'cart.softgoods', if: ofConfig.showSoftGoodAuthorizations } --><!-- /ko -->

                        <div class="item-card__prod-edit" data-bind="if: viewModel.allowWarehouseSelection() && !viewModel.useMultiShipEditUI">
                            <!-- ko template: { name: 'cart.productEditLink', data: { title: 'Change Warehouse', linkText: 'Change Warehouse', detailLine: $data } } --><!-- /ko -->
                        </div>

                        <!-- ko if : ofConfig.bShowCartOptions && cartOption -->
                        <p class="item-card__cart-opt" data-bind="text: cartOption"></p>
                        <!-- /ko -->

                        <!-- ko template: { name: 'cart.additionalDetailLineInfo', data: $data } --><!-- /ko -->
                    </figcaption>
                </figure>
            </td>

            <td class="item-card__price">
                <b class="tablesaw-cell-label">Unit Price</b>
                <span class="item-card__original-price" data-bind="html: ofConfig.showPricingOrderEntry ? instanceUnitPriceDisplay : utils.drawHidePriceMessage()"></span>
            </td>

            <!-- ko if :  viewModel.useMultiShipEditUI() || $data.qtyDisplayType() =='text' || !viewModel.allowProductAdds() && !$data.editing() -->
                <td class="cart-item-price__qty">
                    <b class="tablesaw-cell-label">Qty</b>
                    <label>
                        <input class="cart-item-price__qty-input" type="text" data-bind="attr: { value: viewModel.getTotalQty(instance()) }" disabled/>
                        <!-- ko if:ofConfig.showUom -->
                            <span class="cart-item-price__uom" data-bind="text: $data.uom"></span>&nbsp;
                        <!-- /ko -->
                        <span class="cart-item-price__saved-cart-label" data-bind="html: 'On ' + ofConfig.SavedCartLabel"></span>
                    </label>
                </td>
            <!-- /ko -->

            <!-- ko if : !viewModel.useMultiShipEditUI() && $data.qtyDisplayType() =='input' &&  viewModel.allowProductAdds() && !$data.editing()-->
                <td class="cart-item-price__qty">
                    <b class="tablesaw-cell-label">Qty</b>
                    <div class="cart-item-price__qty-wrapper">
                        <input type="number" class="cart-item-price__qty-input"
                            data-bind="
                                value: qty,
                                attr: {
                                    'id' : 'qty-ship-' + orderDetailKey(),
                                    'min' : minQty() || 1,
                                    'step' : qtyIncrement() || 1,
                                    'max' : maxQty() || undefined
                                },
                                validateQty
                            ">
                        <label class="cart-item-price__qty-label">
                            <!-- ko if:ofConfig.showUom -->
                                <span class="cart-item-price__uom" data-bind="text: $data.uom"></span>
                            <!-- /ko -->
                            <span class="cart-item-price__saved-cart-label" data-bind="html: 'On ' + ofConfig.SavedCartLabel"></span>
                            <span
                                class="cart-item-price__order-detail-key"
                                data-bind="
                                    attr:
                                    {
                                        'data-key' : orderDetailKey()
                                    },
                                    visible:  minQty() > 1 || maxQty() > 1 || qtyIncrement() > 1">
                                <a href="#0"
                                    class="cart-item-price__info-btn"
                                    data-trigger="hover"
                                    data-html="true"
                                    data-placement="top"
                                    data-bind="popover, attr: {
                                        'data-content': oConfig.labels.minQty + ': ' + minQty() + '<br>' + oConfig.labels.step  + ': ' + qtyIncrement() + '<br>' + oConfig.labels.maxQty + ': ' + maxQty()
                                    }">
                                    <i class="fas fa-question-circle"></i>
                                </a>
                            </span>
                        </label>
                    </div>
                </td>
            <!-- /ko -->

            <!-- ko if: viewModel.recordType() === 'recurring' && !editing()-->
            <td class="item-card__order-items-recurring">
                <b class="tablesaw-cell-label">Qty</b>
                <div class="item-card__order-items-label visible-xs visible-sm">Schedule</div>
                <!-- ko template: { name: 'cart.recurringLineDetails' } --><!-- /ko -->
            </td>
            <!-- /ko -->

            <td class="item-card__total">
                <b class="tablesaw-cell-label">Total</b>
                <div class="item-card__cart-ext-price" data-bind="html: ofConfig.showPricingOrderEntry ? utils.formatMoney(price() * viewModel.getTotalQty(instance())) : utils.drawHidePriceMessage()"></div>
            </td>

            <!-- ko if:$data.editing() && viewModel.mainProduct() -->
                <td class="item-card__edit">
                    <!-- ko template: { name: 'catalog.detail_info', data:viewModel.mainProduct } --><!-- /ko -->

                    <div class="item-card__child-selector-wrapper">
                        <span class="item-card__child-selector" data-bind="template: { name: 'catalog.child_selectors', if: viewModel.mainProduct().childSelectors, data: viewModel.mainProduct().childSelectors }"></span>
                    </div>

                    <!-- ko template: { name:'catalog.atc_full', data:viewModel.mainProduct().selectedProduct } --><!-- /ko -->
                </td>
            <!-- /ko -->

            <td class="item-card__prod-edit prod-edit">
                <!-- ko if: viewModel.showRemoveLink($data) -->
                    <a class="prod-edit__del-btn text-danger" role="button" data-bind="event: { click: viewModel.removeProduct }, visible: !editing()" title="Remove this product from your Order?">
                        Remove
                    </a>
                <!-- /ko -->

                <!-- ko if: viewModel.allowProductAdds() && ofConfig.allowProductEditInEditView -->
                    <!-- ko template: { name: 'cart.productInlineEditLinks' } --><!-- /ko -->
                <!-- /ko -->

            </td>
        </tr>

        <tr class="config-options__row -no-border-top" data-bind="if: configuratorJson.choices">
            <td class="config-options__column" colspan="5">
                <!-- ko template: { name: 'cart.configOptions', data: $data } --><!-- /ko -->
            </td>
        </tr>

        <tr id="cartAdvSettings" class="item-card__adv-settings collapse -adv-settings">
            <td class="item-card__adv-settings-cell"></td>
            <td class="item-card__adv-settings-cell">
                    <b class="tablesaw-cell-label">Change Price</span>&nbsp;<a href="javascript:void(0);" class="price-helper__help-tip-tooltip" data-bind="tooltip:{}" title="Change any input below and all other inputs will update automatically.">

                    <i class="fas fa-question-circle"></i></a></b>
                <!-- ko if : viewModel.superUserOrderFormMode() && ofConfig.superUserAllowProductPriceEdits && $data.qtyDisplayType() == 'input' && !$data.editing() -->
                    <!-- ko if: ofConfig.showSUPriceControls && (!isNaN(commodity.cost()) || !isNaN(commodity.retailPrice())) -->
                        <!-- ko template: 'cart.priceHelper' --><!-- /ko -->
                    <!-- /ko -->
                <!-- /ko -->
            </td>
            <td class="item-card__adv-settings-cell">
                <b class="tablesaw-cell-label">Change Qty Limits</span>&nbsp;<a href="javascript:void(0);" class="qty-ctrl-settings__help-tip-tooltip" data-bind="tooltip:{}" title="Customers can change the qty, but only within these limits.">

                <i class="fas fa-question-circle"></i></a></b>
                <!-- ko if : viewModel.allowQtyControls() -->
                    <!-- ko template: 'cart.qtyControlSettings' --><!-- /ko -->
                <!-- /ko -->
            </td>
            <td class="item-card__adv-settings-cell"></td>
            <td class="item-card__adv-settings-cell"></td>
        </tr>


</script>

<script type="text/html" id="cart.productInlineEditLinks">
    <span class="product-edit">
        <a href="" style="display: block" data-bind="event: { click: viewModel.editProduct }, visible: !editing()" title="Edit this Product" class="product-edit__edit">
            <small>Edit</small>
        </a>
        <a href="" style="display: block; wrap: none;" data-bind="event: { click: viewModel.cancelEditProduct }, visible: editing" title="Cancel edits" class="product-edit__cancel">
            <small>cancel</small>
        </a>
    </span>
</script>

<script type="text/html" id="cart.instanceCloneLink">
    <a class="global-modal instanceCloneLink"
        data-bind="attr: { href: 'clone_instances.asp?modal=1&payment=1&source_key=' + viewModel.orderKey() + '&source_instances=' + detailLine.instance(),
                            'data-title': oConfig.labels.cloneInstanceTitle },
                            html: oConfig.labels.cloneInstanceLink,
                            addModalHandler: { 'element' : $('.instanceCloneLink'),
                                                'handler' : viewModel.genericModalComplete
                            },
                    visible: !viewModel.completed()"></a>
</script>

<script type="text/html" id="cart.productEditLink">
    <a class="global-modal productEditLink"
        data-bind="attr: { href: 'pc_product_detail.asp?key=' + detailLine.productID() + '&od_key=' + detailLine.orderDetailKey(),
                            'data-title': title },
                            html: linkText,
                            addModalHandler: { 'element' : $('.productEditLink'),
                                                'handler' : viewModel.genericModalComplete
                            },
                    click: function() { utils.setActiveQuote(viewModel.orderKey()); return true; },
                    visible: !viewModel.completed() && viewModel.allowProductAdds()"
        data-size="large"></a>
</script>

<script type="text/html" id="cart.selectShipTo">

    <!-- ko if: ofConfig.useProductSummaryTableView -->
        <div class="row-fluid checkout-multiship-row single-ship table-view">
            <div class="ship-to-select u-checkout-well" data-bind="visible: shipments().length > 0 ">
                <h3 class="u-checkout-well__title">Select Address</h3>
                <div class="shipping-actions__button" data-bind="if: ofConfig.bAllowShipToAdds">
                    <!-- ko template: 'cart.addAddressButton' --><!-- /ko -->
                </div>
                <div class="address-select">
                    <div class="address-select__group input-append" data-bind="with: shipments()[0]">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                    </div>

                </div>
            </div>
            <!-- ko template: { name: 'cart.productQuickAdd', if: viewModel.allowProductAdds() && ofConfig.showProductQuickAddInEditView } --><!-- /ko -->
            <div class="items-on-order u-checkout-well">
                <h3 class="u-checkout-well__title" data-bind="html: 'Products On ' + ofConfig.SavedCartLabel "></h3>
                <!-- ko if: viewModel.superUserOrderFormMode() && ofConfig.superUserAllowProductPriceEdits && itemsOnOrder().length -->
                    <span class="product-settings">
                        <a id="onOrderAdvBtn" data-bind="event: { click: function() { $('#cartAdvSettings.collapse').toggleClass('in'); $('#onOrderAdvBtn').toggleClass('active'); } }" title="Advanced Settings?" class="btn btn-default on-order__adv-settings">
                            <i class="fas fa-cog"></i> <span class="on-order__adv-settings-text"> Price/Qty Overrides</span>
                        </a>
                    </span>
                <!-- /ko -->
                <table class="item-list tablesaw tablesaw-stack -tablesaw-break0" role="presentation">
                        <thead data-bind="if: $data.itemsOnOrder().length > 0" class="item-list__thead">
                            <tr class="item-list__head-row">
                                <th class="item-list__head-title">Description</th>
                                <th class="item-list__head-title">Unit Price</th>
                                <th class="item-list__head-title">Qty</th>
                                <th class="item-list__head-title">Total</th>
                                <th class="item-list__head-title">Remove</th>
                            </tr>
                        </thead>
                        <tbody data-bind="foreach: $data.itemsOnOrder">
                            <!-- ko if: parentProductID().trim() == '' || !hasParentInCart() -->
                                <!-- ko template: 'cart.itemCard'--><!-- /ko -->
                            <!-- /ko -->
                        </tbody>
                    <div class="alert alert-info" data-bind="visible: $data.detailLines().length == 0, html: 'There are currently no Products on this ' + oConfig.labels.savedCarts + '. Please use the \'Add Products\' section above to search for and add products.'"></div>
                </table>
            </div>
        </div>
    <!-- /ko -->

    <!-- ko ifnot: ofConfig.useProductSummaryTableView -->
        <div class="row-fluid checkout-multiship-row single-ship">
            <div class="ship-to-select span6" data-bind="if: shipments().length > 0 ">
                <div class="address-select">
                    <label>Ship to this address</label>
                    <div class="address-select__group input-append" data-bind="with: shipments()[0]">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                    </div>
                </div>
            </div>
            <div class="items-on-order span6">
                <label data-bind="html: 'Products on ' + ofConfig.SavedCartLabel + ':'"></label>
                <div class="item-list">
                    <div data-bind="foreach: $data.itemsOnOrder">
                        <!-- ko if: parentProductID().trim() == '' || !hasParentInCart() -->
                        <div class="media" data-bind="template: 'cart.itemCard'"></div>
                        <!-- /ko -->
                    </div>
                </div>
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipToSelectOptGroups">
    <!-- ko if: ofConfig.useAddressFindPopup -->
        <!-- ko template: { name: 'cart.addressFinder', data: shipTo } --><!-- /ko -->
        <!-- ko  if: $data.shipTo().key-->
        <a class="btn edit-shipto global-modal"
            data-title="Edit Shipping Address"
            data-size="large" data-bind="
                addModalHandler: { 'element' : $('.edit-shipto'), 'handler' : function(data){  changeAddressFromFinder(data, $data) } },
                attr: {
                    'href': 'account.asp?modalaction=editshipto&modal=1&o_key=' + viewModel.orderKey() + '&sha_id=' + $data.shipTo().key()
                },
                visible: viewModel.allowShaEdits() && $data.shipTo().global() == 0
            ">Edit</a>
        <!-- /ko -->
    <!-- /ko -->
    <!-- ko if: !ofConfig.useAddressFindPopup -->
        <select class="shipto-select"
                data-bind="
                    foreach: viewModel.addressTypes(),
                    value: shipTo

        ">
            <optgroup data-bind="attr: {'label': $data.label }, foreach: $parent.availableAddresses">
            <!-- ko if: $data.global() == $parent.global -->
                <option data-bind="
                    value: $data,
                    text:  $data.name()"></option>
            <!-- /ko -->
            </optgroup>
        </select>
        <a class="btn edit-shipto global-modal"
            data-title="Edit Shipping Address"
            data-size="large" data-bind="
                addModalHandler: { 'element' : $('.edit-shipto'), 'handler' : function(data){ apiGetShippingAddresses(data.sha_key.value); } },
                attr: {
                    'href': 'account.asp?modalaction=editshipto&modal=1&o_key=' + viewModel.orderKey() + '&sha_id=' + $data.shipTo().key()
                },
                visible: viewModel.allowShaEdits() && $data.shipTo().global() == 0
            ">Edit</a>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.addressFinder">
    <div id="address_selector" class="formrow ">
        <div class="rightcol controls">
            <input
                type="text"
                name="sha_key_disp"
                size="39"
                data-bind="
                    value: name,
                    attr: { 'id': viewModel.getAddressFinderId('sha_key_disp', $data, $parent) }
                "
                readonly />
            <a
                role="button"
                data-bind="
                    attr: {
                        'id': viewModel.getAddressFinderId('address_finder', $data, $parent),
                        'name': viewModel.getAddressFinderId('address_finder', $data, $parent),
                        'href': encodeURI('modal_search.asp?sql_id=Base_Shipping_Addresses&version=0&revision=2&cat_id=&extrafields=nm,s_add1,s_add2,s_city,s_state,s_zip,CONCAT(s_add1, \', \', s_add2, \' (\', sha.nm, \')\') as sha_key_disp&filter=|AND|(searchexact~sha.status~1|OR|isnull~sha.status)|AND|(searchexactnot~hide_in_cart~1|OR|isnull~hide_in_cart)|AND|(((isnull~sha.globaladdress~|OR|searchexactnot~sha.globaladdress~@1))|OR|(|AND|(searchexact~sha.c_id~|OR|searchexact~sha.a_id~)))&orderby=sha.s_add1~&cols=nm;Nickname;nm;;nm;1;1;;1;~s_add1;Address+1;sha.s_add1;;sha.s_add1;1;1;;1;~s_city;City;sha.s_city;;sha.s_city;1;1;;1;~s_state;State;sha.s_state;;sha.s_state;1;1;;1;~s_zip;Zip;sha.s_zip;;sha.s_zip;1;1;;1;&fields=sha_key_disp;sha_key_disp;text~sha_key;sha_key;text&drawstyles=1&classicstyle=0&primary=sha_key&usedistinct=0&showactions=1&use_aqt=0&loadblank=' + ofConfig.addressFindBlankOnLoad )
                    },
                    addModalHandler: { 'element' : $('#' + viewModel.getAddressFinderId('address_finder', $data, $parent)), 'handler' : function(data){ changeAddressFromFinder(data, $parent) } }"
                class="btn btn-primary global-modal"
                data-size="large"
                data-title="Your Address Book" >
            Find</a>
        </div>
    </div>
</script>

<script type="text/html" id="cart.assignItemsToShipTos">
    <!-- ko template: { name: 'cart.productQuickAdd', if: viewModel.allowProductAdds() && ofConfig.showProductQuickAddInEditView } --><!-- /ko -->
    <div class="checkout-multiship" data-bind="foreach: $data">
        <!-- ko if: parentProductID().trim() == '' || !hasParentInCart() -->
        <div class="checkout-multiship__row u-checkout-well">
            <table class="checkout-multiship__table tablesaw tablesaw-stack -tablesaw-break0" role="presentation">
                <thead class="item-list__thead">
                    <tr class="item-list__head-row">
                        <th class="item-list__head-title">Description</th>
                        <th class="item-list__head-title">Unit Price</th>
                        <th class="item-list__head-title">Qty</th>
                        <th class="item-list__head-title">Total</th>
                        <th class="item-list__head-title">Remove</th>
                    </tr>
                </thead>
                <tbody class="checkout-multiship__item">
                    <!-- ko template: 'cart.itemCard'--><!-- /ko -->
                </tbody>
            </table>

            <div class="checkout-multiship__address u-well">
                <!-- div data-bind="foreach: viewModel.itemShipToMap().filter(function(shipToMap){ return shipToMap.instance() == instance() }) " -->
                <div class="checkout-multiship__address-items" data-bind="foreach: viewModel.itemShipToMap().filter(function(shipToMap){ return shipToMap.orderDetailKey == orderDetailKey() }) ">
                    <div class="input-prepend input-append">
                        <input type="number" class="qty-input"
                            data-bind="
                                value: qty,
                                attr: {
                                    'id' : 'qty-ship-' + orderDetailKey,
                                    'min' : $parent.minQty() || 1,
                                    'step' : $parent.qtyIncrement() || 1,
                                    'max' : $parent.maxQty() || undefined
                                },
                                disable: $parent.qtyDisplayType() == 'text',
                                validateQty
                            ">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                        <!-- ko if: $index() != 0 -->
                            <span class="remove-shipto__add-on add-on">
                                <a class="remove-shipto__button btn btn-default" href="#" data-bind="click: removeItemToShipToMap, attr: { 'data-index' : $index}"><i class="icon-remove"></i></a>
                            </span>
                        <!-- /ko -->
                    </div>
                    <button
                        class="btn btn-link btn-small split-this"
                        type="button"
                        data-bind="
                            attr : {
                                'data-split' : parseFloat(qty())
                            },
                            visible: qty() > minQty() && (parseFloat(qty()) >= parseFloat(qtyIncrement() * 2)) && $parent.qtyDisplayType() == 'input',
                            text: ofConfig.splitThisItemText,
                            click: moveItemToNewShipTo
                        ">
                    </button>
                </div>
            </div>
        </div>
        <!-- /ko -->
    </div>
</script>

<script type="text/html" id="cart.itemShipToMapPreview">
     <table class="tablesaw" data-tablesaw-mode="stack" role="presentation">
        <thead>
            <th>#</th>
            <th>Ship to address</th>
            <th>Products in shipment</th>
            <th>&nbsp;</th>
        </thead>
        <tbody data-bind="foreach: _.uniq(_.invoke(viewModel.itemShipToMap(),'shipTo'))">
            <tr>
                <td>
                    <!-- ko template: { name: 'cart.addressSummaryInfo', data: $data } --><!-- /ko -->
                </td>
                <td>
                    <span class="" data-bind="foreach: viewModel.itemShipToMap().filter(function(shipToMap){ return shipToMap.shaKey() == $data.key() }) ">
                        <ul class="unstyled" data-bind="foreach: viewModel.itemsOnOrder().filter(function(item){ return item.orderDetailKey() == orderDetailKey })">
                            <li><span class="badge" data-bind="text: qty"></span> <span data-bind="html : name"></span></li>
                        </div>
                    </span>
                </td>
                <td class="cell-center">
                    <button class="btn btn-inverse"><i class="icon-trash"></i></button>
                </td>
            </tr>
        </tbody>
    </table>
</script>

<script type="text/html" id="cart.itemsList">
    <table class="tablesaw table cart-table tablesaw-stack" data-tablesaw-mode="stack" role="presentation">
        <!-- ko if: viewModel.useMultiShipEditUI() && !viewModel.allItemsAllocated() -->
            <thead>
                <th></th>
                <th>
                    Description
                </th>
                <th>
                    Qty
                </th>
                <th>
                    Product Price
                </th>
                <th>
                    Total
                </th>
            </thead>
        <!-- /ko -->
        <!-- ko if: viewModel.allItemsAllocated() || !viewModel.useMultiShipEditUI() -->
            <thead>
                <th>
                    Description
                </th>
                <th>
                    Qty
                </th>
                <th>
                    Product Price
                </th>
                <th>
                    Total
                </th>
            </thead>
        <!-- /ko -->
        <tbody class="cart-row-std" data-bind="foreach: $data">
            <!-- ko if: parentProductID().trim() == '' || !hasParentInCart() -->
            <tr data-bind='css: { "alert alert-warning": viewModel.useMultiShipEditUI() && allocatedQty() !== qty() }'>
                <!-- ko if: viewModel.useMultiShipEditUI() && !viewModel.allItemsAllocated() -->
                    <td>
                        <span data-bind="if: qty() != allocatedQty()"><i class="icon-warning-sign"></i> <span data-bind="text: qty() - allocatedQty()"></span> unallocated</span>
                    </td>
                <!-- /ko -->
                <td class="media">
                    <img
                        data-bind="visible: !oConfig.fastTrack,attr : { alt: sku() + ' - ' + name(),
                                src: utils.buildImagePath(commodity.pic.thumb()) }"
                        class="media-object pull-left cart-item-pic"
                        onerror="utils.handleImageError(this)">
                    <div class="media-body">
                        <div class="cart-item-sku" data-bind="text: sku"></div>
                        <!-- ko if : ofConfig.bShowCartOptions && cartOption -->
                        <p data-bind="text: cartOption"></p>
                        <!-- /ko -->
                        <!-- ko template: { name: "cart.configOptions", data: $data } --><!-- /ko -->
                        <!-- ko template: { name: "cart.additionalDetailLineInfo", data: $data } --><!-- /ko -->
                        <!-- ko if: viewModel.recordType() === 'recurring' -->
                            <div class="flex-table-column order-items-recurring">
                                <div class="order-items-label visible-xs visible-sm">Schedule</div>
                                <!-- ko template: { name: 'cart.recurringLineDetails' } --><!-- /ko -->
                            </div>
                        <!-- /ko -->
                        <div class="cart-item-name" >
                            <span data-bind="html: name"></span>
                            <!-- ko if: promoID -->
                                <span class="promo-icon" data-bind="attr: { 'title' : promoDescription() } ">P</span>
                            <!-- /ko -->
                        </div>
                    </div>
                </td>
                <td>
                    <span data-bind="text: qty"></span>
                    <!-- ko if: viewModel.useMultiShipEditUI -->
                        &nbsp;(<span data-bind="text: allocatedQty"></span> assigned)
                    <!-- /ko -->
                </td>
                <td>
                    <span data-bind="html: utils.formatMoney(priceBeforeAdjustment() || price())"></span>
                </td>
                <td>
                    <span data-bind="html: utils.formatMoney((priceBeforeAdjustment() || price()) * qty())"></span>
                </td>
            </tr>
            <!-- /ko -->
        </tbody>
    </table>
</script>

<script type="text/html" id="cart.priceHelper">
    <span class="price-helper">
        <b class="price-helper__help-tip">
            <span class="price-helper__help-tip-text">Change Price</span>&nbsp;<a href="javascript:void(0);" class="price-helper__help-tip-tooltip" data-bind="tooltip:{}" title="Change any input below and all other inputs will update automatically.">
                <i class="fas fa-question-circle"></i>
            </a>
        </b>
        <label class="price-helper__price-override">
            <div class="input-prepend input-append price-helper__override-group">
                <span class="add-on">$</span>
                <input type="number" class="input-small price-helper__override-input" step=".01" data-bind="
                    value: price,
                    attr: {
                        'id' : 'price-' + orderDetailKey()
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                ">
                <span class="price-helper__help-tip add-on">
                    Default Price
                </span>
                <!-- ko if: priceCalculationType() == 'fixed' -->
                    <a href="#0" class="add-on price-helper__override-action" data-bind="event: { click: viewModel.resetSuperUserPriceOverride }, html: ofConfig.superUserResetPriceHelpText"></a>
                <!-- /ko -->
            </div>
        </label>
        <p class="price-helper__min text-small text-info" data-bind="if: viewModel.superUserRestrictMinPrice() && superUserMinPrice() != null && superUserMinPrice()">
            <span data-bind="html: utils.formatMoney(superUserMinPrice())"></span>&nbsp;Minimum
        </p>
        <label class="price-helper__commodity commodity">
            <!-- ko if: commodity.cost() > 0 -->
                <div class="input-append commodity__cost">
                    <input class="qty-input commodity__cost-markup" type="number" step="1" data-bind="
                        value: markupPercent,
                        attr: {
                            'id' : 'markupPercent-' + orderDetailKey(),
                            'min': minMarkupPercent
                        },
                        event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">&percnt; Markup</span>
                </div>
            <!-- /ko -->

            <!-- ko if: commodity.retailPrice() -->
                <div class="input-append commodity__discount">
                    <input type="number" class="qty-input commodity__discount-input" step="1" data-bind="
                    value: discountPercent,
                    attr: {
                        'id' : 'discountPercent-' + orderDetailKey(),
                        'max': maxDiscountPercent
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">&percnt; Discount</span>
                </div>
            <!-- /ko -->
            <!-- ko if: commodity.cost() -->
                <div class="input-append commodity__gross-mar-perc">
                    <input class="qty-input commodity__gross-mar-perc-input" type="number" step="1" data-bind="
                    value: grossMarginPercent,
                    attr: {
                        'id' : 'grossMarginPercent-' + orderDetailKey(),
                        'min': minGrossMarginPercent
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">&percnt; Gross Margin</span>
                </div>
            <!-- /ko -->
            <!-- ko if: commodity.cost() -->
                <div class="input-prepend commodity__gross-mar-usd">
                    <span class="add-on">$</span>
                    <input type="number" class="qty-input" step=".01" data-bind="
                    value: grossMarginAmount,
                    attr: {
                        'id' : 'grossMarginAmount-' + orderDetailKey(),
                        'min': minGrossMarginAmount
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">$ Gross Margin</span>
                </div>
            <!-- /ko -->
        </label>
    </span>
</script>

<script type="text/html" id="cart.qtyControlSettings">
    <div class="qty-ctrl-settings">
        <!-- ko if: $data.qtyDisplayType() =='input' -->
            <b class="qty-ctrl-settings__help-tip">
                <span class="qty-ctrl-settings__help-tip-text">Change Qty Limits</span>&nbsp;<a href="javascript:void(0);" class="qty-ctrl-settings__help-tip-tooltip" data-bind="tooltip:{}" title="Customers can change the qty, but only within these limits.">
                    <i class="fas fa-question-circle"></i>
                </a>
            </b>
            <div class="qty-ctrl-settings__max-qty input-append">
                <input name="minQty" type="number" min="1" class="qty-ctrl-settings__qty-input"
                    data-bind="
                        value: suMinQty,
                        attr: {
                            'id' : 'minQty' + orderDetailKey()
                        }
                    "><label class="add-on" for="minQty">Min Qty</label>
            </div>
            <div class="qty-ctrl-settings__min-qty input-append">
                <input name="maxQty" type="number" min="0" class="qty-ctrl-settings__qty-input input-append"
                    data-bind="
                        value: suMaxQty,
                        attr: {
                            'id' : 'maxQty' + orderDetailKey()
                        }
                    "><label class="add-on" for="maxQty">Max Qty</label>
            </div>
            <div class="qty-ctrl-settings__qty-increment input-append">
                <input name="qtyIncrement" type="number" min="1" class="qty-ctrl-settings__qty-input input-append"
                    data-bind="
                        value: suQtyIncrement,
                        attr: {
                            'id' : 'qtyIncrement' + orderDetailKey()
                        }
                    "><label class="add-on" for="qtyIncrement">Qty Increment</label>
            </div>
        <!-- /ko -->
        <!-- TODO: Do we need to hide if original removeType == 'hide'? -->
        <label class="checkbox">
            <input type="checkbox" data-bind="checked: allowDeletes, attr: { id: 'allowDeletes-' + orderDetailKey() }">
            Allow deletes
        </label>
    </div>
</script>

<script type="text/html" id="cart.paymentMethods">
    <ul class="nav nav-tabs" data-bind="foreach: payMethods">
        <li data-bind=" css: { active: $parent.paymentMethod.paymentMethodKey() === $data.paymentMethodKey() } ">
            <a data-bind="attr: {
                            id: paymentMethodKey,
                            'data-content': name,
                            href: '#method_' + paymentType()
                        },
                        text: name,
                        click: $parent.setPaymentMethod,
                        clickBubble: true"
                data-toggle="pill"
                rel="popover"
                data-trigger="hover"
                data-placement="top"></a>
        </li>
    </ul>
    <div class="tab-content">
        <div class="payment-method-ds muted" data-bind="visible: ofConfig.showPayMethodDescription, html: paymentMethod.description()"></div>
        <div id="method_cc" class="tab-pane" data-bind="css: { active: paymentMethodID() && paymentMethod.paymentType() == 'cc' }">
            <div data-bind="template : { name: 'cart.creditCardForm' }"></div>
        </div>
        <div id="method_billme" class="tab-pane" data-bind="visible: paymentMethodID() && paymentMethod.paymentType() == 'billme' ">
        </div>
        <div id="method_ach-check" class="tab-pane" data-bind="visible: paymentMethodID() && paymentMethod.paymentType() == 'ach-check' ">
            <h3>-- ACH is not implemented yet, but would go here --</h3>
            <!-- drawAchCheckForm -->
        </div>
        <div id="method_paypal" class="tab-pane" data-bind="visible: paymentMethodID() && paymentMethod.paymentType() == 'paypal'">
        </div>
        <div id="controlgroup_invoice_ponumber" class="control-group" data-bind="if: paymentMethodID && paymentMethod.collectPO()">
            <label for="ponumber" class="control-label" data-bind="html: ofConfig.POLabel"></label>
            <div class="controls">
                <input type="text" class="controlgroup-invoice__ponumber-input -short-input" name="ponumber" id="ponumber" data-bind="value: poNumber, attr: {
                    maxlength: ofConfig.POMaxLength,
                    required: viewModel.paymentMethod.poRequired() == true ? 'required' : null }" />
                <input type="hidden" id="ponum_required" value="0" data-bind="if: !viewModel.paymentMethod.poRequired()"/>
                <!-- ko if: !viewModel.paymentMethod.poRequired() -->
                    <p id="ponum_help" class="help-block text-small" data-bind="html: ofConfig.POLabelHelp"></p>
                <!-- /ko -->
                <input type="hidden" id="ponum_required" value="1" data-bind="visiblef: viewModel.paymentMethod.poRequired()"/>
                    <p id="ponum_help" class="help-block text-small" data-bind="visible: viewModel.paymentMethod.poRequired()">(required)</p>
            </div>
        </div>
        <div id="controlgroup_invoice_comments" class="control-group" data-bind="visible: ofConfig.showFulfillmentcomments">
            <label for="order_comments" class="control-label">
                <strong data-bind="text: ofConfig.fulfillmentCommentsText"></strong>
            </label>
            <div class="controls">
                <textarea type="text" name="order_comments" id="order_comments" autocomplete="off" data-bind="value: comments"></textarea>
                    <p class="help-block text-small">(optional)</p>
            </div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.productSelectList">
<!-- ko if: $data -->
    <div id="modal_add_prods" class="modal fade hide" data-backdrop="static" data-max-height="400">
        <div class="modal-header">
            <h3>Select Products to Ship</h3>
        </div>
        <div class="modal-body">
            <div class="list-group list-group-flex js-shipItemSelect" data-bind="if: detailsMap">
                <!-- ko foreach: detailsMap -->
                    <span data-forasdf="checkout_item_1" class="list-group-item">
                    <!-- was a label, changed to span to keep checkbox from being erroneously
                        changed as you click other elements in the list item, will drive check
                        box off of qty, and set qty to 0 if checkbox is un-checked by user -->
                        <div class="flex-item checkbox">
                            <input type="checkbox" id="checkout_item_1" data-bind="checked: toggleItemSelect, attr : { disabled: unallocatedQty() == 0 && qtyToShip() == 0} " />
                        </div>
                        <div class="flex-item flex-item-grow media checkout-multiship-item">
                            <img data-bind="attr : { alt: detailLine.sku() + ' - ' + detailLine.name(), src: utils.buildImagePath(detailLine.commodity.pic.thumb()) }"
                                class="media-object pull-left" onerror="utils.handleImageError(this)" />
                            <div class="media-body">
                                <div class="media-heading">
                                    <div class="text-trim" style="max-width: 20em;" data-bind="attr: { 'title': detailLine.sku() + ' - ' + detailLine.name() }">
                                        <span data-bind="text: detailLine.sku"></span> - <span data-bind="text: detailLine.name"></span>
                                    </div>
                                </div>
                                <table class="table table-condensed text-xsmall">
                                    <tbody>
                                        <tr>
                                            <td>Total Qty</td>
                                            <td class="cell-right" data-bind="text: totalOrderQty"></td>
                                        </tr>
                                        <tr>
                                            <td>Currently included in this shipment</td>
                                            <td class="cell-right">
                                                <span data-bind="text: qtyToShip"></span>
                                                &nbsp;
                                                <!-- ko if:ofConfig.showUom -->
                                                <span class="uom" data-bind="text: detailLine.uom"></span>
                                                <!-- /ko -->
                                            </td>
                                        </tr>
                                        <tr>
                                            <td>Included in all shipments</td>
                                            <td class="cell-right" data-bind="text: qtyInAllShipments"></td>
                                        </tr>
                                        <tr>
                                            <td>Remaining</td>
                                            <td class="cell-right" data-bind="text: unallocatedQty"></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                        <div class="flex-item">
                            <label for="multi_prod_qty_1">Include</label>
                            <input type="number"
                                id="multi_prod_qty_1"
                                class="qty-input"
                                min="0"
                                data-bind="attr: { max: Number(unallocatedQty()) + Number(qtyToShip()) }
                                    , value: qtyToShip, restrictedQty"
                             />
                        </div>
                    </span>
                <!-- /ko -->
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button>
            <button type="button" id="btn_add_to_shipment" class="btn btn-primary" data-bind="click: selectItemsComplete, clickBubble: false">Update shipment</button>
        </div>
    </div>
<!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentSummaryList">
    <!-- ko foreach: shipments -->
        <div class="list-group u-checkout-well">

            <h3 class="u-checkout-well__title">Shipment Summary List</h3>

            <div class="list-group-item" data-bind="visible: $parent.useMultiShipEditUI">
                <h5>
                    <!-- ko template: { name: 'cart.addressSummaryInfo', data: shipTo } --><!-- /ko -->
                </h5>
            </div>

            <div class="list-group-item">
                <!-- ko template: { name: 'cart.shipmentItemTable' } --><!-- /ko -->
                <div class="list-group-item__content-row row-fluid">
                    <div class="list-group-item__content-span span4" data-bind="if: selectedShipVia">
                        <div class="list-group-item__content">
                            <b>Shipping Method:</b>
                            <div>
                                <span data-bind="text: selectedShipVia.name"></span>
                                <!-- ko if : ofConfig.bShowShipTotalMessage -->
                                (<span data-bind="text: ofConfig.sShipTotalText"></span>)
                                <!-- /ko -->
                                <!-- ko ifnot: ofConfig.bShowShipTotalMessage -->
                                    <!-- ko if: ofConfig.bShowPriceText && selectedShipVia.total() == 0  -->
                                        (<span data-bind="text: ofConfig.sShipTotalText"></span>)
                                    <!-- /ko -->
                                    <!-- ko if: !ofConfig.bShowPriceText || selectedShipVia.total() > 0 -->
                                        (<span data-bind="html: utils.formatMoney(selectedShipVia.total())"></span>)
                                    <!-- /ko -->
                                <!-- /ko -->
                            </div>
                        </div>
                    </div>
                    <div class="list-group-item__content-span span4" data-bind="if: ofConfig.UseRequestedDay">
                        <div class="list-group-item__content">
                            <b>Will be shipped on: </b>
                            <div data-bind="text: requestedShipDate"></div>
                        </div>
                    </div>
                    <div class="list-group-item__content-span span4" data-bind="if: !ofConfig.UseRequestedDay && ofConfig.showExpectedShipDate">
                        <div class="list-group-item__content">
                            <b>Will be shipped on: </b>
                            <div data-bind="text: expectedShipDate"></div>
                        </div>
                    </div>
                    <!-- ko if : ofConfig.bShowShipmentComment -->
                        <div class="list-group-item__content-span span4">
                            <div class="list-group-item__content">
                                <b data-bind=" html : ofConfig.sShipmentCommentTitle + ':'"></b>
                                <div data-bind=" html : comments() ? comments : 'No ' + ofConfig.sShipmentCommentTitle"></div>
                            </div>
                        </div>
                    <!-- /ko -->
                </div>

            </div>

        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentList">
     <!-- ko foreach: shipments -->
        <div class="row-fluid shipment-list u-checkout-well" data-bind="attr: { id: key }">
            <h3 class="u-checkout-well__title">Shipment Details</h3>
            <div class="list-group shipment-list__group">
                <div class="shipment-list__text"
                    title="Edit This Shipment">
                    <!-- ko if: !viewModel.isOverLineLimit() -->
                        <a class="btn shipment-list__link" href="#0" data-bind="click:
                        function() {
                            viewModel.shippingComplete(false)
                        }">
                            <i class="icon-pencil"></i> <span data-bind="html: ofConfig.sEditShipmentText"></span>
                        </a>
                    <!-- /ko -->
                    <!-- ko if: viewModel.isOverLineLimit() -->
                        <a class="btn shipment-list__link global-modal" data-size="large" onclick="$('#handle-modal-exit').val(true)" data-bind="attr: { 'href': '/showcart.asp?o_key=' + ofConfig.OKey }">
                            <i class="icon-pencil"></i> <span data-bind="html: ofConfig.sEditShipmentText"></span>
                        </a>
                    <!-- /ko -->
                </div>

                <div class="shipment-list__item">
                    <div class="shipment-title well">
                        <!-- ko template: { name: 'cart.addressSummaryInfo', data: shipTo, if: !showShippingAddressEdit() && shipToValid() } --><!-- /ko -->
                        <!-- ko template: { name: 'cart.shipmentSplitByDisplay', if: ofConfig.showWarehouseOnShipment } --><!-- /ko -->
                    </div>
                </div>

                <!-- ko if : ofConfig.useProductSummaryTableView -->
                    <div class="shipment-list__table-wrapper">
                        <!-- ko template: { name: 'cart.shipmentItemTable' } --><!-- /ko -->
                    </div>

                    <div class="list-group-item">
                        <div class="row-fluid">
                            <div data-bind="if: ofConfig.bUsingShipping, css: { span7: ofConfig.bShowShipmentComment || ofConfig.UseRequestedDay || ofConfig.bUseExpectedShipDate }">
                                <div class="shipment-list__options" >
                                    <h4 data-bind="html: ofConfig.shipmentListChooseMethodLabel">Choose a Shipping Method</h4>
                                    <!-- ko template: { name: 'cart.shipmentMethodSelector' } --><!-- /ko -->
                                </div>
                                <!-- ko template: { if : ofConfig.CollectShipAccount, name: 'cart.shipperAccountSelector' }--><!-- /ko -->
                            </div>
                            <div class="span5 shipment-list__comments" data-bind="if: ofConfig.bShowShipmentComment || ofConfig.UseRequestedDay || ofConfig.bUseExpectedShipDate">
                                <h4 data-bind=" html : ofConfig.sShipmentCommentTitle"></h4>
                                <!-- ko template: { if: ofConfig.bShowShipmentComment, name: 'cart.shipmentGiftOptions' } --><!-- /ko -->
                                <!-- ko template: { if: ofConfig.UseRequestedDay, name: 'cart.requestedShipDate' } --> <!-- /ko -->
                                <!-- ko template: { if: ofConfig.bUseExpectedShipDate, name: 'cart.expectedShipDate' } --><!-- /ko -->
                            </div>
                        </div>
                    </div>
                <!-- /ko -->

                <!-- ko if : !ofConfig.useProductSummaryTableView -->
                    <div class="list-group-item">
                        <div class="row-fluid">
                            <div class="span5">
                                <!-- ko template: { name: 'cart.shipmentItemList' } --><!-- /ko -->
                            </div>
                            <div class="span7">
                                <h4 data-bind="html: ofConfig.shipmentListChooseMethodLabel">Choose a Shipping Method</h4>
                                <!-- ko template: { name: 'cart.shipmentMethodSelector' } --><!-- /ko -->
                                <!-- ko template: { if: ofConfig.bShowShipmentComment, name: 'cart.shipmentGiftOptions' } --><!-- /ko -->
                                <!-- ko template: { if: ofConfig.UseRequestedDay, name: 'cart.requestedShipDate' } --> <!-- /ko -->
                                <!-- ko template: { if: ofConfig.bUseExpectedShipDate, name: 'cart.expectedShipDate' } --><!-- /ko -->
                            </div>
                        </div>
                    </div>
                <!-- /ko -->
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentSplitByDisplay">
    <div class="ship-from" data-bind="html: $data.shipFrom.name"></div>
</script>

<script type="text/html" id="cart.errorMessage">
    <p class="cart__error-message" data-bind="visible: field.isModified() && !field.isValid(), text: field.error"></p>
</script>

<script type="text/html" id="cart.processingOverlay">
    <div class="sk-three-bounce--full-screen">
        <div class="sk-three-bounce">
            <div class="sk-child sk-bounce1"></div>
            <div class="sk-child sk-bounce2"></div>
            <div class="sk-child sk-bounce3"></div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.expirationDate">
    <div class="control-group" data-bind="if: (superUserOrderFormMode() && ofConfig.superUserAllowExpirationDateEdits) || viewModel.isValidDate(expirationDate())">
        <label class="control-label">Expires On</label>
        <div class="controls">
            <!-- ko if: superUserOrderFormMode() && ofConfig.superUserAllowExpirationDateEdits -->
            <div class="input-append">
                <input type="text" class="input-medium" id="ExpirationDate"
                    style="background-color: white;cursor: pointer"
                    readonly="readonly"
                    data-bind="attr: { disabled: viewModel.orderPlaced }
                        , datepicker: expirationDate
                        , datepickerOptions: {
                            minDate: (new Date(expirationDate())) < new Date() ? new Date(expirationDate()) : new Date(),
                            maxDate: moment(new Date()).add(ofConfig.maxExpirationDays, 'days').toDate(), //TODO: this should be configurable
                            constrainInput: true,
                            showOn:'both',
                            buttonText: '<i class=\'icon-calendar\'></i>',
                            beforeShowDay: function (date) {
                                var currentExpiration = (new Date(expirationDate())).getTime();
                                var checkDate = date.getTime();
                                var todayDate = (new Date());
                                todayDate.setHours(0,0,0,0);
                                var today = todayDate.getTime();
                                validDate = checkDate == currentExpiration || checkDate >= today;
                                return [validDate];
                            }
                        }">
                <button type="button" class="btn" data-bind="attr: { disabled: viewModel.orderPlaced }, click: function(shipment) { $('#ExpirationDate').datepicker('show') }, clickBubble: false">
                    <i class="icon-calendar"></i>
                </button>
            </div>
            <!-- /ko -->
            <!-- ko if: !superUserOrderFormMode() || !ofConfig.superUserAllowExpirationDateEdits -->
                <span data-bind="text: expirationDate"></span>
            <!-- /ko -->
        </div>
    </div>
</script>

<script type="text/html" id="cart.softgoods">
    <!-- ko if: $data.orderFlags.indexOf("create_softgoods_auth") >= 0 -->
        <span data-bind="text: oConfig.labels.softgoods"></span>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.backorderMessage">
    <!-- ko if: (qty() - Math.max(0, commodity.qtyAvailable() - commodity.qtyBuffer())) > 0 && ofConfig.backorderMessageText -->
        <span data-bind="html: ofConfig.backorderMessageText.replace(/<BO>/g, '{{BO}}').replace(/<SHIPPING>/g, '{{SHIPPING}}').replace(/{{BO}}/g, qty() - Math.max(0, commodity.qtyAvailable() - commodity.qtyBuffer())).replace(/{{SHIPPING}}/g, Math.max(0, commodity.qtyAvailable() - commodity.qtyBuffer()))"></span>
    <!-- /ko -->
</script>



<script type="text/html" id="cart.recurringDetails">
    <h3 class="recurring-details__title u-checkout-well__title">
        Recurring Order Details
    </h3>
    <!-- ko if: viewModel.lifecycleStage() == "recurring-preprocessed" -->
        <div class="alert alert-warning">This order has recently been preprocessed and changes made here could affect the order being processed.</div>
    <!-- /ko -->
    <!-- ko if: viewModel.lifecycleStage() == "recurring-pending" -->
        <div class="alert alert-error">This order has recently been cloned and changes made here will not be reflected on the current order being processed.</div>
    <!-- /ko -->
    <!-- ko if: viewModel.lifecycleStage() == "recurring-disabled" -->
        <div class="alert alert-info">This order is currently disabled and will not be processed on the date selected.</div>
    <!-- /ko -->
    <div id="recurring_details" class="form-horizontal checkout-payment-form" >
        <div class="control-group input-append">
            <label class="control-label" for="ro_rundate"><strong>Next order date:</strong></label>
            <div class="controls">
                <input type="text" id="ro_rundate" class="input-medium"
                    style="background-color: white;cursor: pointer"
                    readonly="readonly"
                    data-bind="datepicker: roRunDate, value: moment(roRunDate()).format('MM/DD/YYYY')
                        , datepickerOptions: {
                            minDate: viewModel.getMinimumRecurringOrderDate(),
                            constrainInput: true,
                            showOn:'both',
                            buttonText: '<i class=\'icon-calendar\'></i>'
                        }">
                </div>
        </div>

        <div class="control-group">
            <label  class="control-label"for="ro_rec_qty"> <strong>Place order every: </strong></label>
            <div class="controls input-append u-flex">
                <input id="ro_rec_qty" class="qtyinput" data-bind="value: roRecQty" type="number" min="1">
                <select  id="ro_rec_case" class="input-medium" data-bind="value: roRecCase">
                    <option value="day">Day(s)</option>
                    <option value="week">Week(s)</option>
                    <option value="month">Month(s)</option>
                    <option value="year">Year(s)</option>
                </select>
            </div>
        </div>
    </div>
</script>

<script type="text/html" id="cart.recurringLineDetails">
    <span class="ro-actions">
        <select id="ro_actions" data-bind="value: selectedRoAction, event:{ change: viewModel.updateRecurringType }">
            <option value="recurring" data-bind="text: ofConfig.roRecurringSelectText"></option>
            <option value="fixed" data-bind="text: ofConfig.roOneTimeSelectText"></option>
            <option value="skipnext" data-bind="text: ofConfig.roSkipSelectText"></option>
        </select>
    </span>
</script>


</div><!-- include files here -->


<script type="text/javascript">

	//Menu variables
	var quickAccessLinks = processQuickLinks(JSON.parse("[]"));
	var menuDrawerPanels = document.getElementsByClassName('menu-drawer__menu');
	var toolbarBtns = document.getElementsByClassName('toolbar__btn');
	var filterInput = document.getElementById('link-filter');
	var filterForm = document.getElementById('filterSearch');
	var activeToolbarBtn;
	var activeMenuDrawerPanel;

	var quickAccessLinkViewModel = {
		quickAccessLinks: ko.observableArray(quickAccessLinks),
		getQuickAccessClass: function(url) {
			var buttonClass = "add-to-quick-access";
			var inList = _.some(this.quickAccessLinks(), function(qal) {
				return qal.href.includes(url);
			});

			if(inList) {
				return buttonClass + "  add-to-quick-access-added";
			} else {
				return buttonClass;
			}
		}
	};

	var qaConfig = {
		menuTitle: "Quick Access",
		showLinks: false,
		useFilter: false			
	}

	function processQuickLinks(data){
		var quickLinks = [];
		_.each(data, function(link){
			//create add link if missing.
			if(!link.addLink || !link.addLink.href){
				link.addLink = {};
			}else{
				link.addLink = removeDomainName(link.addLink.href);
			}
			//remove base url since it gets tracked with the local url.
			link.href = removeDomainName(link.href);
			quickLinks.push(link);
		});
		return quickLinks;
	}
	
	function removeDomainName(url) {
		var parts = url.split(/^[A-Za-z0-9+.-]+:\/\/[^/]+\/+(.*)/);
		if (parts.length < 2) return url;
		return parts[1];
	}

	if(typeof Config != "undefined" && (qaConfig.showLinks || qaConfig.useFilter)){
		var sApiBaseUrl = Config.apiBaseUrl;
		var sessionKey = "D79FD399538C4F9E919FD94A412B0F0C";

		function addEventHandlersToLinks() {
			if (qaConfig.showLinks && $("#menuDrawer").length > 0) {

				var linkHrefs = _.pluck(quickAccessLinkViewModel.quickAccessLinks(), 'href');
				var existingLinks = {};
				for (var i in linkHrefs) {
					existingLinks[linkHrefs[i]] = true;
				}
				function attributesByAddedStatus(element) {
					var link = element.closest('li')[0].querySelector('a');
					if (link && existingLinks[link.href.replace(/^.*\/\/[^\/]+/, '')]) {
						return 'class="add-to-quick-access add-to-quick-access-added" disabled';
					} else {
						return 'class="add-to-quick-access"';
					}
				}

				$.each($('#menuDrawer .filter-menu ul li > .childlink__actions'), function() {
					$(this).append(
						'<button ' + attributesByAddedStatus($(this)) + ' title="Add to ' + qaConfig.menuTitle + '" onclick="addToQuickAccess(this); return false;">' +
						'<i class="fas fa-star"></i>' +
						'</button>'
					);
				});

				// Find top level links that require a favorite button
				$.each($('#menuDrawer .filter-menu .linkset__li-1'), function() {
					if ($(this).children('a').attr('href') !== '#' && $(this).children('a').attr('href') !== 'javascript:void(0);') {
						$(this).append(
							'<div class="childlink__actions">' +
							'<button ' + attributesByAddedStatus($(this)) + ' title="Add to ' + qaConfig.menuTitle + '" onclick="addToQuickAccess(this); return false;">' +
							'<i class="fas fa-star"></i>' +
							'</button>' +
							'</div>');
					}
				});

				$.each($('#menuDrawer .filter-menu .linkset-dashboard__li-2:not(:has(.childlink__actions)), #menuDrawer #linkset-dashboard-user .linkset-dashboard-user__li-1:not(:has(.childlink__actions))'), function() {
					// Find the linkset data-generated manage links and add the favorites button and addedit button
					$(this)
						.append(
							'<div class="childlink__actions">' +
							'<button ' + attributesByAddedStatus($(this)) + ' title="Add to ' + qaConfig.menuTitle + '" onclick="addToQuickAccess(this); return false;">' +
							'<i class="fas fa-star"></i>' +
							'</button>' +
							'</div>')
						.next('.linkset__li-2.add')
						.children('a')
						.detach()
						.prependTo($(this).children('.childlink__actions'))
						.addClass('add')
						.removeClass('linkset__a-2')
						.html('<i class="icon-pencil"></i>');

					// Find the linkset data-generated addedit buttons and move them to the correct place in the markup
					$('.filter-menu .linkset__li-2.manage + .linkset__li-2.add').remove();
				});
					
				// Find the linkset data-generated links (not manage) and add the favorites button
				$.each($('#menuDrawer .filter-menu .linkset__li-2:not(.manage):not(:has(.childlink__actions))'), function() {
					$(this).append(
						'<div class="childlink__actions">' +
						'<button ' + attributesByAddedStatus($(this)) + ' title="Add to ' + qaConfig.menuTitle + '" onclick="addToQuickAccess(this); return false;">' +
						'<i class="fas fa-star"></i>' +
						'</button>' +
						'</div>');
				});
					
			}

			// Listen for keyup, then send to debounce function
			if (qaConfig.useFilter) {
				//Save the active menu when the user clicks the filter.  this is to make sure KO is ready.
				$("#link-filter, .menu-drawer__filter-search").on('click focus', function(){
					activeLink = $(".linkset a.active");
				});
				$("#link-filter, .menu-drawer__filter-search").on('keyup reset', function () {
					linkSearch();
					//Close the active menu before filtering.
					if($('#link-filter').val() == ''){
						activeLink.addClass('active');
					}else{
						activeLink.removeClass('active');
						$('.filter-alert').hide();
					}
				});
			}
		}

		var linkSearch = _.debounce(debouncedSearch, 250);

		function debouncedSearch() {
			
			clearFilter();
			// Track our filter value
			var filter = filterInput.value;

			if( filter == '' ) {
				$('.filter-alert').show('slow');
				return false;
			}

			// Find the current active menu panel and store it
			for (var i = 0; i < toolbarBtns.length; i++) {
				if (toolbarBtns[i].classList.contains("active")) {
					activeToolbarBtn = toolbarBtns[i].dataset.menu;
					activeMenuDrawerPanel = document.getElementById(activeToolbarBtn);
				}
			}

			// Make sure all the menus are active while filtering, with case exceptions
			for (var i = 0; i < menuDrawerPanels.length; i++) {
				if (!menuDrawerPanels[i].classList.contains("active")) {

					// Hide the titles
					menuDrawerPanels[i].getElementsByClassName('menu-drawer__menu-title')[0].classList.add("hidden");

					switch (menuDrawerPanels[i].id) {
						case "quickMenu":
						case "quickAddMenu":
						case "accountMenu":
							break;
						default:
							menuDrawerPanels[i].classList.add("active");
						}
					}

				// Hide the current title
				menuDrawerPanels[i].getElementsByClassName('menu-drawer__menu-title')[0].classList.add("hidden");
			}	

			// Loop the remaining links. If you match on an A tag, show it's direct LI, and any parent/child with link-parent as a class.
			$(".filter-menu ul li > a").each(function () {
				try{
					setAccordionHeight(false);
					if ( $(this).text().search(new RegExp(filter, "i")) >= 0 || ( $(this).data('section') && $(this).data('section').search(new RegExp(filter, "i")) >= 0 ) ){
						// Match. Show this link's LI and any parent/child li.link-parent with the search term highlighted
						$(this).addClass('partial-highlight').removeClass('highlight').highlight(filter);
						$(this).parent().show();

						// Show any parent dropdown for the link being shown	
						$(this).parent().parents('li.link-parent').show().addClass('open');

						// Show any child elements of the link being shown
						$(this).parent().find('li').show();
						$(this).parent().find('li.link-parent').removeClass('open');
					} else if ( false && $(this).attr('href').search(new RegExp(filter, "i")) >= 0) {
						//Turned this off for now, it was doing weird things when only an ADD link was found.
						//TODO: investigate to see if we can fix the weird bug mentioned above.

						// Match. Show this link's LI and any parent/child li.link-parent 
						$(this).addClass('highlight');
						$(this).parent().show();

						// Show any parent dropdown for the link being shown	
						$(this).parent().parents('li.link-parent').show().addClass('open');

						// Show any child elements of the link being shown
						$(this).parent().find('li').show();
						$(this).parent().find('li.link-parent').removeClass('open');
					} else {
						$(this).removeClass('highlight');
						$(this).unhighlight()
						$(this).parent().hide();
					}

				}catch(error){ console.error(error); }
			
			});

			// Loop just the top levels to see if a non-parent matches the filter.
			$(".filter-menu > li > a").each(function () {
				
				if ($(this).text().search(new RegExp(filter, "i")) < 0) {
					//no match was found on the parent but
					//Only it if the sub links didn't trigger a match
					if(!$(this).parent().hasClass('open')){ 
						$(this).parent().hide();
						$(this).removeClass('highlight');
					}

					$('#quickAddMenu').removeClass('active');
					$('#quickMenu').removeClass('active');

				} else {
					$(this).parents('.menu-drawer__menu').find('.menu-drawer__menu-title').removeClass('hidden');
					$(this).addClass('partial-highlight').removeClass('highlight').highlight(filter);

					//If this is a parent top level, enable all links below but collapse the menu
					if ($(this).parent().hasClass('link-parent')) {
						if(!$(this).parent().hasClass('open')){ 
							$(this).click();
						}
						$(this).next('ul').children('li').show();
						setAccordionHeight(false);
					}
					
				}
			});

			// Check to see if we have an empty filter value
			if (filter.length === '') {
				clearFilter();
			} else {
				// Check to see if the key we are pressing is the ESC key
				filterInput.addEventListener("keydown", function (event) {
					if (event.keyCode === 27) {
						filterForm.reset();
						clearFilter();
					}
				});
			}

			$('.toolbar__btn').click(function() {
				clearFilter();
				filterForm.reset();
				clearFilter();
			});
		}

		// Clear all the filter classes and reset to original active menu
		function clearFilter() {

			// Reset the classes
			$('.partial-highlight').unhighlight().removeClass('partial-highlight');
			$('.highlight').removeClass('highlight');
			$('.hidden').removeClass('hidden');
			$('.filter-menu li, .filter-menu li.link-parent.drop').removeClass('open').show();

			// Find the active parent and re-add the open class			
			$('.filter-menu a.active').parents('li.link-parent.drop:not(.open)').addClass('open');

			if ($('#quickAddMenuBtn').hasClass('active')) {
				$('#quickAddMenu').addClass('active');
			} else {
				$('#quickAddMenu').removeClass('active');
			}

			if ($('#quickMenuBtn').hasClass('active')) {
				$('#quickMenu').addClass('active');
			} else {
				$('#quickMenu').removeClass('active');
			}

			//Clear active menus
			for (var i = 0; i < menuDrawerPanels.length; i++) {
				if (menuDrawerPanels[i].classList.contains("active")) {
					menuDrawerPanels[i].classList.remove("active");
					menuDrawerPanels[i].getElementsByClassName('menu-drawer__menu-title')[0].classList.remove("hidden");
				}
			}

			//Only show the active menu if there is no filter
			if($('#link-filter').val() == ''){
				//Reset to the current open menu panel
				if (activeMenuDrawerPanel && !activeMenuDrawerPanel.classList.contains("active")) {
					activeMenuDrawerPanel.classList.add("active");
				}
			}
		}
		
		function addToQuickAccessKO(data, event) {addToQuickAccess(event.target, data.useGlobalModal)};

		function addToQuickAccess(el, useGlobalModal=null) {
			$(el).addClass('add-to-quick-access-added');
			$(el).attr("disabled", true);

			var link = $(el).closest('li')[0].querySelector('a');
			var href = link.href.replace(/^.*\/\/[^\/]+/, '');
			var name = link.innerText.trim();
			var key = $(el).closest('li')[0].dataset.key;
			var bSave = true;

			try {
				_.each(quickAccessLinkViewModel.quickAccessLinks(), function (link) {
					if (link.href == href && link.name == name) {
						//don't save a duplicate
						bSave = false;
					}
				});

				if (bSave) {
					var basePayload	= {
							href: href,
							name: name,
							key: key,
							addLink:{},
					};
					if(useGlobalModal){
						basePayload.useGlobalModal = useGlobalModal();
					} 
					

					if ($(link).closest('li')[0].classList.contains('manage') && $(link).closest('li')[0].querySelector('.add').length > 0) {
						var childHref = link.nextElementSibling.querySelector('a').href.replace(/^.*\/\/[^\/]+/, '');
						var childName = "+";
						var childKey = link.nextElementSibling.querySelector('a').dataset.key;

						basePayload.addLink = {
								href: childHref,
								name: childName,
								key: childKey
						};
					}

					quickAccessLinkViewModel.quickAccessLinks.push(basePayload);
					saveQuickLinks();
				}
			} catch (err) {
				console.log(err);
			}
			return false;
		}

		var saveQuickLinks = _.debounce(debouncedSave , 1000);

		function removeFromQuickAccess(link){

			try{
				quickAccessLinkViewModel.quickAccessLinks.remove(link)
				saveQuickLinks();
			}catch(err){
				console.log(err);
			}
			return false;
		}

		function debouncedSave(){
			console.log('saving...');
			$.ajax({
				url: Config.apiBaseUrl + 'UserConfigurations/properties/QuickAccessLinks',
				type: 'POST',
				headers: { 'Authorization' : 'Bearer ' + sessionKey},
				contentType: 'application/json',
				dataType: 'json',
				data: ko.mapping.toJSON(quickAccessLinkViewModel.quickAccessLinks),
				success: function(data) {
					utils.popToastr('Success', 'Quick Access Links saved');
				},
				error: Utilities.ajaxError('Error Saving Data')
			})			
		}

		function isEmpty(obj){
			if(!obj) return false;

			for(var prop in obj) {
				if(obj.hasOwnProperty(prop))
					return false;
			}

			return JSON.stringify(obj) === JSON.stringify({});	
		}

		$( function(){
			addEventHandlersToLinks();
			markActiveCategory();
		});
	}

	jQuery.extend({
		highlight: function (node, re, nodeName, className) {
			if (node.nodeType === 3) {
				var match = node.data.match(re);
				if (match) {
					var highlight = document.createElement(nodeName || 'span');
					highlight.className = className || 'highlight';
					var wordNode = node.splitText(match.index);
					wordNode.splitText(match[0].length);
					var wordClone = wordNode.cloneNode(true);
					highlight.appendChild(wordClone);
					wordNode.parentNode.replaceChild(highlight, wordNode);
					return 1; //skip added node in parent
				}
			} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
					!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
					!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
				for (var i = 0; i < node.childNodes.length; i++) {
					i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
				}
			}
			return 0;
		}
	});

	jQuery.fn.unhighlight = function (options) {
		var settings = { className: 'highlight', element: 'span' };
		jQuery.extend(settings, options);

		return this.find(settings.element + "." + settings.className).each(function () {
			var parent = this.parentNode;
			parent.replaceChild(this.firstChild, this);
			parent.normalize();
		}).end();
	};

	jQuery.fn.highlight = function (words, options) {
		var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
		jQuery.extend(settings, options);

		if (words.constructor === String) {
			words = [words];
		}
		words = jQuery.grep(words, function(word, i){
		return word != '';
		});
		words = jQuery.map(words, function(word, i) {
		return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
		});
		if (words.length == 0) { return this; };

		var flag = settings.caseSensitive ? "" : "i";
		var pattern = "(" + words.join("|") + ")";
		if (settings.wordsOnly) {
			pattern = "\\b" + pattern + "\\b";
		}
		var re = new RegExp(pattern, flag);

		return this.each(function () {
			jQuery.highlight(this, re, settings.element, settings.className);
		});
	};

</script>



<script type="text/html" id="links.quickAccessLinks">

	<div id="quick_access_links">
		<span class="menu-drawer__menu-content qa-noresults" data-bind="visible: !quickAccessLinks().length">
			<p>To add a link for quick access, press the star icon that appears in menu items. For example:</p>
			<ul class="linkset accordion linkset__ul-1">
				<li class="linkset__li-1">
					<a href="https://coresite.cimproduction.com" class="qa-example linkset__a-1">Home Page</a>
					<div class="childlink__actions">
						<button class="add-to-quick-access" title="Add to Bookmarks" onclick="addToQuickAccess(this); return false;">
							<i class="fas fa-star"></i>
						</button>
					</div>
				</li>
			</ul>
		</span>
		
		<div class="quick-access__container" data-bind="visible: quickAccessLinks().length > 0 ">
			<div
				data-bind="sortable: 
				{
					data: quickAccessLinks,
					afterMove: saveQuickLinks,
					containment: 'parent'
				}">

				<ul class="quick-access__wrapper linkset accordion linkset__ul-1" data-bind="css: { hybrid: addLink && !isEmpty(addLink) && $data.addLink.href != '' }">
					<li class="linkset__li-1" data-bind="css: { manage: !isEmpty(addLink) && $data.addLink.href != '' }">
						<a class="quick-access linkset__a-1" 
							data-bind="
								attr: { href : $data.href, id: 'ql_' + $index() }, 
								css: {'global-modal': function() { return $data.useGlobalModal == 'TRUE' }()}, 
								click: 
									function() {
										if($data.useGlobalModal == 'TRUE'){
											addGlobalModalHandlerBySelector('#ql_' + $index(), function() {window.location.href = window.location.href});
										}else{
											window.location.href = $data.href;
										}
									} 
								">
							<span data-bind="attr: { class : 'qa-delete delete-button-' + $index() }">
								<i class="icon-remove qa-remove"  data-bind="click: removeFromQuickAccess" title="Remove from Quick Access"></i>
							</span>
							<span data-bind="html: $data.name "></span>
						</a> 
						<div class="childlink__actions" data-bind="if: !isEmpty(addLink) && $data.addLink.href != ''">
							<a class="add" data-bind="attr: { 'href': addLink.href }">
								<i class="icon-pencil"></i>
							</a>
						</div>
					</li>
				</ul>

			</div>
		</div>
	</div>
</script>
    <div class="hide browser-alert -bottom">
        <div class="browser-alert__title">
            <strong class="browser-alert__title-text">
            Browser Compatibility Warning
            </strong>
            <button type="button" class="browser-alert__close" onclick="acknowledgeBrowserAlert()">
            <svg width="10" height="9" viewBox="0 0 10 9" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M6.54688 4.5L8.89062 2.15625C9.19531 1.875 9.19531 1.40625 8.89062 1.125L8.375 0.609375C8.09375 0.304688 7.625 0.304688 7.34375 0.609375L5 2.95312L2.63281 0.609375C2.35156 0.304688 1.88281 0.304688 1.60156 0.609375L1.08594 1.125C0.78125 1.40625 0.78125 1.875 1.08594 2.15625L3.42969 4.5L1.08594 6.86719C0.78125 7.14844 0.78125 7.61719 1.08594 7.89844L1.60156 8.41406C1.88281 8.71875 2.35156 8.71875 2.63281 8.41406L5 6.07031L7.34375 8.41406C7.625 8.71875 8.09375 8.71875 8.375 8.41406L8.89062 7.89844C9.19531 7.61719 9.19531 7.14844 8.89062 6.86719L6.54688 4.5Z" fill="white"/>
            </svg>
            </button>
        </div>
        <div class="browser-alert__text">
            The browser you are using is not supported on this site. You may experience issues with some features on the site. It is recommended that you use one of the following browsers - Chrome, Edge, Firefox, or Safari.
        </div>
    </div>
    <script>
        function acknowledgeBrowserAlert(){
            document.querySelector('.browser-alert').style.display = 'none';
            document.cookie = 'browseralert=1';
        }

        if(parseInt(getInternetExplorerVersion()) <= 11){
            jQuery('.browser-alert').show();
        }
    </script>
    </body>

</html>
