<!DOCTYPE html>

<!--[if IE]><![endif]-->
<!--[if IE 9]> <html class="no-js ie9 lt-ie10"> <![endif]-->
<!--[if gt IE 9]><!--> <html lang="en" class="no-js"> <!--<![endif]-->



<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=1">
	
	

	<title>San Benito Shutter | Plantation Shutter Components | United States</title>
	<meta name="description" content="Build a partnership with San Benito Shutter, the industry leading distributor of wood and poly shutter components. At SBS we've expanded the reach of our distribution and are excited about forthcoming innovations to change the way you interact with your business.">
	<meta name="keywords" content="cal wood, components, hidden tilt, highland shutters, lewis cabinet, louver, norman, poly, poly wood, poplar, raw wood, shutter, shutter components, shutter manufacturer, shutter panel">
		<meta name="robots" content="noindex">
    <link href="https://fonts.googleapis.com/css?family=Work+Sans:400,500,700|Heebo:400,500,700" rel="stylesheet">
<link rel="stylesheet" href="templates/fa/css/font-awesome.min.css">

    <!-- Favicon -->

    <link rel="shortcut icon" type="image/x-icon" href="gfx/favicon/favicon.ico">
    <link rel="apple-touch-icon-precomposed" sizes="57x57" href="gfx/favicon/apple-touch-icon-57x57.png" />
    <link rel="apple-touch-icon-precomposed" sizes="114x114" href="gfx/favicon/apple-touch-icon-114x114.png" />
    <link rel="apple-touch-icon-precomposed" sizes="72x72" href="gfx/favicon/apple-touch-icon-72x72.png" />
    <link rel="apple-touch-icon-precomposed" sizes="144x144" href="gfx/favicon/apple-touch-icon-144x144.png" />
    <link rel="apple-touch-icon-precomposed" sizes="60x60" href="gfx/favicon/apple-touch-icon-60x60.png" />
    <link rel="apple-touch-icon-precomposed" sizes="120x120" href="gfx/favicon/apple-touch-icon-120x120.png" />
    <link rel="apple-touch-icon-precomposed" sizes="76x76" href="gfx/favicon/apple-touch-icon-76x76.png" />
    <link rel="apple-touch-icon-precomposed" sizes="152x152" href="gfx/favicon/apple-touch-icon-152x152.png" />
    <link rel="icon" type="image/png" href="gfx/favicon/favicon-196x196.png" sizes="196x196" />
    <link rel="icon" type="image/png" href="gfx/favicon/favicon-96x96.png" sizes="96x96" />
    <link rel="icon" type="image/png" href="gfx/favicon/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="gfx/favicon/favicon-16x16.png" sizes="16x16" />
    <link rel="icon" type="image/png" href="gfx/favicon/favicon-128.png" sizes="128x128" />
    <meta name="application-name" content="San Benito Shutter" />
    <meta name="msapplication-TileColor" content="#FFFFFF" />
    <meta name="msapplication-TileImage" content="gfx/favicon/mstile-144x144.png" />
    <meta name="msapplication-square70x70logo" content="gfx/favicon/mstile-70x70.png" />
    <meta name="msapplication-square150x150logo" content="gfx/favicon/mstile-150x150.png" />
    <meta name="msapplication-wide310x150logo" content="gfx/favicon/mstile-310x150.png" />
    <meta name="msapplication-square310x310logo" content="gfx/favicon/mstile-310x310.png" />

	<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?0ec437f">
		<link rel="stylesheet" href="css/dashboard.css?0ec437f">
	
    <link rel="stylesheet" href="css/notemplate.css?0ec437f">


<script src="code/js_hooks.asp?0ec437f"></script>
<script>
// This function is needed for JS hooks.
function getOriginalPageName() {
	return 'signin.asp';
}
</script>


<script>
var pendoData = {
        visitor: {
            id:          '-sbshutter',
            key:         '',
            package:     '2',
            template:    '',
            firstName:   '',
            lastName:    '',
            email:       '',
            companyName: '',
            companyNum:  '',
            role:        'standard'
        },
        account: {
            id:          'sbshutter',
            key:         '698545A045C24E04A8C6595EA503C960',
            package:     '2'
        },
        session: {
            loggedIn:     'False',
            superUser:    'False',
            viewingChild: '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>
<script src="/js/bundles/coreTop.js?0ec437f0f8d6e44a30e900b9c815b7a843abecc0" ></script>
<script>
	$( document ).ready(function() {
		$( '.promo' ).insertBefore( '.page-main>.container-fluid');
		$( '.promo' ).removeClass( 'hide' );
	  });
</script>
</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" 
    
	    data-bind="css: { 'modal-open': viewModels.detailSlideOut && viewModels.detailSlideOut().isOpen() }"
    
>
    
    
    <header class="page-header text-center">
        <div class="container-fluid">
            
	<a href="https://sbshutter.cimproduction.com" class="logo">
	  <img src="https://d370ry6d2q1pi0.cloudfront.net/images/san-benito-shutter-logo-color.png" alt="San Benito Shutter Logo">
	</a>
	
        </div>
    </header>
    <div id="signedOutContent" class="container-fluid">
        
    <div class="app-signin dash-landing">
        
            <div class="app-signin-form text-center">
                

<script language="JavaScript">

	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="well well-large" style="">
		<form
			name="custacctlogin"
			class="custom-account-login"
			id="custacctlogin"
			method="POST"
			action="https://sbshutter.cimproduction.com/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 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 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">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" href="request_username.asp" target="_top">
						Forgot your username?
					</a>
				</li>
				<li class="login-links__reset-password">
					<a id="pass_reset_link" href="request_password_reset.asp" target="_top">
						Reset your password
					</a>
				</li>
				<li class="login-links__create-login">
					<a href="create_login_select_acct.asp">Create a login for your existing San Benito Shutter account</a>
				</li>
				<li class="login-links__create-account">
					<a class="" href="https://sbshutter.cimproduction.com/create_login_and_account.asp" target="_top">
						Sign up for a new 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://sbshutter.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">
    <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="clickCanvasToCloseNav"></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="app-loading hide">
    <svg id="appLoadingSpinner" class="app-loading-spinner" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="170px" height="170px" viewBox="-220 312 170 170" enable-background="new -220 312 170 170" xml:space="preserve">
	<g class="app-loading-spinner-svg">
		<path fill="#AAAAAA" d="M-67.6,398.2l13.5-4c-0.3-5.9-1.1-11.6-2.4-17l-14-0.3c-0.5-1.6-1.1-3-1.6-4.6l10.8-8.9 c-2.4-5.1-5.4-10.2-8.6-14.8l-13.2,5.1c-1.1-1.3-2.2-2.4-3.2-3.5l6.5-12.4c-4.3-3.8-8.9-7.3-13.8-10.2l-10,9.7 c-1.3-0.8-3-1.3-4.3-2.2l1.3-14c-5.4-1.9-10.8-3.5-16.7-4.3l-5.7,12.9c-1.6-0.3-3.2-0.3-4.9-0.3l-4-13.5c-5.9,0.3-11.6,1.1-17,2.4 l-0.3,14c-1.6,0.5-3,1.1-4.6,1.6l-8.9-10.8c-5.1,2.4-10.2,5.4-14.8,8.6l5.1,13.2c-1.3,1.1-2.4,2.2-3.5,3.2l-12.4-6.5 	c-3.8,4.3-7.3,8.9-10.2,13.8l9.7,10c-0.8,1.3-1.3,3-2.2,4.3l-14-1.3c-1.9,5.4-3.5,10.8-4.3,16.7l12.9,5.7c-0.3,1.6-0.3,3.2-0.3,4.9 l-13.5,4c0.3,5.9,1.1,11.6,2.4,17l14,0.3c0.5,1.6,1.1,3,1.6,4.6l-10.8,8.9c2.4,5.1,5.4,10.2,8.6,14.8l13.2-5.1 c1.1,1.3,2.2,2.4,3.2,3.5l-6.5,12.4c4.3,3.8,8.9,7.3,13.8,10.2l10-9.7c1.3,0.8,3,1.3,4.3,2.2l-1.3,14c5.4,1.9,10.8,3.5,16.7,4.3 l5.7-12.9c1.6,0.3,3.2,0.3,4.9,0.3l4,13.5c5.9-0.3,11.6-1.1,17-2.4l0.3-14c1.6-0.5,3-1.1,4.6-1.6l8.9,10.8 c5.1-2.4,10.2-5.4,14.8-8.6l-5.1-13.5c1.3-1.1,2.4-2.2,3.5-3.2l12.4,6.5c3.8-4.3,7.3-8.9,10.2-13.8l-9.7-10c0.8-1.3,1.3-3,2.2-4.3 	l14,1.3c1.9-5.4,3.5-10.8,4.3-16.7l-12.9-5.7C-67.9,401.4-67.6,399.8-67.6,398.2z M-135,437.3c-22.4,0-40.4-18.1-40.4-40.4 c0-22.4,18.1-40.4,40.4-40.4s40.4,18.1,40.4,40.4C-94.6,419.2-112.7,437.3-135,437.3z"></path>
	</g>
	<image class="app-loading-spinner-img" src="templates/gfx/loading/loading.gif" alt="Loading..."></image>
</svg>

</div><div class="dashboard-bot-scripts">
	<div class="global-scripts">
    <script>
        var bValidIp = true;
        var sOfUrl   = 'https://sbshutter.cimproduction.com';

        var jsConfig = {
            static_pages: {
                content_key: '',
                content_type: ''
            }
        }
    </script>

    <script src="code/global_modal_js.asp?0ec437f"></script>
    <script src="../hooks/js_custom_functions.asp?0ec437f"></script>
    <script src="js/vendor/stretchy.min.js?0ec437f" data-filter=".stretchy, .stretchy *"></script>

    <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?0ec437f0f8d6e44a30e900b9c815b7a843abecc0" ></script>
    <script src="js/dashboard.js?0ec437f"></script>
    
</div>
    </div>


    <!-- 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){
					loadInboxData();
				}
			});

			/**
			* Loads the bulk of the data from the api for the current entity.
			*/
			function getDataFromApi(retry) {
				if (retry == null) retry = 3;
				$.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){
						if (retry > 0) setTimeout(function () {
							getDataFromApi(retry - 1);
						}, 100 * Math.pow(2, 3 - retry));
						else {
							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
								]
							})
					}

					$.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 = Config.contextType;
					var 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();
							inbox.close();
						}

										loadAndViewActivity(activity.id(), function(){
						viewModels.data().filterActivities();
					});
				};

				activity.clearNotification = function() {
					$.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() {};

				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() {};

				$.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() && ko.utils.unwrapObservable(viewModels.data().id)) {
						switch(Config.contextType) {
							case 'Account':
							case 'accounts':
								return viewModels.data().name();
							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){
					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();
				$.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);
					}
				});
			}

			Utilities.loadAccountUsers = function (accountId, callback) {
				callback = callback || function() {};

				if (accountId) {
					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() {
				$.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);

					$.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');
						}
					});
				}
			}

			$(function () {
				$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
					var target = $(e.target).attr("href") // activated tab
					if (target ==='#makeCallTab' && !viewModels.isUsersLoaded()) {
						$.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 = {};

						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.');
							}
						});
						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.contextType == 'accounts' && viewModels.data().name) {
					viewModels.accountSelectorList.push({
						id: Config.contextKey,
						name: viewModels.data().name()
					});
					viewModels.data().newActivity.accountId(Config.contextKey);
				}

				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"
				},
				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 = [];
				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: 'su_user_add.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="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>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">
			<h5>Logged By</h5>
			<ul class="icons-ul">
				<li data-bind="with: createdBy"><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>
				<li class="text-warning" data-bind="if: !(account() && account() != {})">
					<i class="icon-li icon-warning-sign"></i> No Account
				</li>
				<li class="text-small muted" style="line-height: 1.4" data-bind="if: !(account() && account() != {})">
					You can assign an account using the form below, under the Related To heading.
				</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>
				<label>Related to</label>
				<div data-bind="ifnot: (account() && account() != {})">
					<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>
			</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">
				<div id="externalComment" class="collapse hidden-note-options">
					<textarea 
						data-bind="textInput: newNote.externalComment" 
						class="input-block-level stretchy" 
						rows="3" 
						placeholder="Type your customer visible comment here" 
						autofocus 
						style="min-height: 100px; padding: 15px;">
					</textarea>
				</div>
				<textarea 
					data-bind="textInput: newNote.internalComment" 
					class="input-block-level stretchy is-note" 
					rows="3" 
					placeholder="Add an internal comment here"
					style="min-height: 100px; 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="card-input input-block-level"
					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>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: 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="min-height: 100px; 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">
			<h5>Customer Info</h5>
			<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>
			<h5>Ticket Details</h5>
			
			<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>Ticket submitted</h1>
						<button class="btn" data-bind="click: startNewTicket">Add Another Ticket</button>
						<a class="btn" href="manage_tickets.asp">Manage Tickets</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="controls 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">&nbsp;</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 class="controls">
						<div data-bind="template: 'crm.tickets.newTicket.categories'"></div>
					</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="close" data-bind="click: viewModels.detailSlideOut().close">&times;</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>
		
		<!-- Payment Page Notes Template ****************************************************************************** -->
		<script type="text/html" id="cart.noteBookComments">
			<div class="entity-comments">
				<div class="control-group">
					<div class="controls">
						<div id="external_comments_wrapper">
							<textarea
								id="external_comments"
								class="input-xlarge"
								rows="3"
								placeholder="Type your comment here"
								data-bind="textInput: viewModels.externalComment">
							</textarea>
							<div data-bind="visible: viewModels.externalComment() != ''  ">
								<a class="text-small btn btn-primary" data-bind="event : { 'click' : viewModels.saveCustomerComment}">Send Comment</a>
							</div>
						</div>
					</div>
				</div>
			</div>
		</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="app-navicon with-badge ">
				<i class="icon-large icon-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.activity.card.heading'"></div>
				</div>
			</a>
		</script>

		<script type="text/html" id="crm.activity.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="flex-slider-frame" data-bind="visible: !activities().length">
				<div class="card">All caught up!</div>
			</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>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>
		var utils = {};

		utils.isMainProduct = function (product) {
			return product && ko.unwrap(viewModel.mainProduct) === product;
		};

		utils.formatProductLink = function(data){
			console.log(data);
		};

		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.getCookie('activequote') && utils.getCookie('activequote').length == 32);

		//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.getParameter = function (param) {
			var value;
			var parameters = window.location.search.replace('?', '');

			if (parameters) {
				var pattern = new RegExp('\\b' + param + '=([^;&]+)', 'gi');
				value = parameters.split(pattern)[1];
			}

			return value || '';
		};

		utils.handleImageError = function (img) {
			if ($(img).attr('src') !== oConfig.noImagePath) {
				$(img).attr('src', oConfig.noImagePath);
			}
		};

		utils.buildImagePath = function(image){
			image = image.replace(oConfig.storefrontUrl, oConfig.sessionData.cdnUrl).toLowerCase();
			image = image.replace('images/images/', 'images/');
			if(!image){
				return oConfig.noImagePath || oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/images/' + oConfig.defaultImage.replace(/^\/+/, '');
			}
			else if(image.indexOf("http") > -1){
				return image.replace(/http:/i, 'https:');
			}
			else if(image.indexOf("/") > -1){
				return oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/' + image.replace(/^\/+/, '');
			}
			else{
				return oConfig.sessionData.cdnUrl.replace(/\/+$/, '') + '/images/' + image.replace(/^\/+/, '');
			}
		}

		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.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 Active ' + 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'
				};

				// 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
					};
				}

				_.forEach(details, function (item) {

					var product = item.selectedProduct();
					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] = product.selectedWarehouse().key || oConfig.defaultWarehouse;

					if(item.type == 'child' && parentKey) {
						data['parent_p_id_' + lineKey] = parentKey;
					}

					data['url_' + lineKey] = item.link();
					data['minqty_' + lineKey]        = product.selectedUom().minQty();
					data['maxqty_' + lineKey]        = product.selectedUom().maxQty();
					data['qty_increment_' + lineKey] = product.selectedUom().step();

					_.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

					runHook('getPostDataBeforeReturn', { self: self, data: data, product: product, 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('Items added to cart' + cartName + ':\n' + _.map(details, function (product) {
					return '\tQty: ' + product.selectedQty() + ' - ' + product.name();
				}).join('\n'));
			}

			function successHandler(responseData, status, request) {
				if(oConfig.isModal) {
					parent.modal.done();
					return;
				}
				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);

				if(viewModel.atcComplete) {
					viewModel.atcComplete();
				}

				postGoogleAnalytics(details); 

				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 item to cart',
					'There was an error',
					errorToastrConfig
				);

			}

			function postGoogleAnalytics(details){
				if(oConfig.t_analytics == "uae"){
					var gtmProducts = []; 

					_.forEach(details, function(item){
						var gtmProduct = {
								'name': item.name(),
								'id': item.sku(),
								'price': item.unitPrice(),
								'quantity': Number(item.selectedQty())
						}
						gtmProducts.push(gtmProduct);
					}); 
					ga('ec:addProduct', gtmProducts); 
					ga('ec:setAction', 'add');
  					ga('send', 'event', 'UX', 'click', 'add to cart'); 
				}
				/* If using GTM pass add to cart event on sucess */ 
				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) {
						dataLayer.push({
							'event': oConfig.t_gtm_add_to_cart_event_name,
							'ecommerce': {
								'currencyCode': 'USD',
								'add': {
									'products': gtmProducts
								}
							}
						});
					}
				}
			}
			
			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) {
			var sPage = "showcart.asp";

			if(utils.isActiveQuote){
				sPage = "payment.asp"
			}
			var confirmToastrConfig = {
				'closeButton': true,
				'newestOnTop': true,
				'onclick': function() {
					window.location = oConfig.sessionData.orderfrontUrl + '/' + 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(' item', details, true) + ' added to ' + oConfig.labels.savedCarts }
				}else{
					var confirmTextConfig = { title: utils.plural(' item', details, true) + ' added to Cart'}
				}
			};

			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(' Item', 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'
				],
				related: productCollectionMapping,
				secondRelated: productCollectionMapping,
				children: productCollectionMapping,
				alsoBought: productCollectionMapping
			}, self);

			self.children.extend({ deferred: true });

			self.atcButtonText = ko.observable('');
			self.atcErrorText = ko.observable('');

			self.updateAtcButtonText = function() {
				if(self.configuratorEditData && self.configuratorEditData.od_id) {
					self.atcButtonText(oConfig.labels.updateCartItem || 'Update');
				} else if (utils.isActiveQuote) {
					self.atcButtonText('Add Active ' + 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.isParent = function() {
				if (self.type.toLowerCase() === 'parent'){
					return true;
				}else{
					return false;
				}	
			}

			self.requireInfoForAtc = ko.computed(function () {
				return !!(self.isParent() || self.useConfigurator() || self.hasCartOptions());
			});

			self.priceDisplay = ko.observable(function () {
				var template = 'catalog.details_link';

				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;
				}
				return template;
			}());

			self.selectedQty = ko.observable(function() {
				if(self.configuratorEditData) {
					return self.configuratorEditData.qty;
				} else {
					return undefined;
				}
			}());

			//self.selectedQty = ko.observable();

			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 certainaly 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
							}
						});
					}

					return uom;
				})());
				
			_.each(self.uomPrice(),function(uom){
				var bHasBreaks = false;
				bHasBreaks = uom.breaks().length > 0;
				uom.hasBreaks(bHasBreaks);
			});

			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;
					price = lineBreak.price();
					startQ = lineBreak.qty();
					endQ = lineBreak.qtyEnd();

					if (endQ != '0') {
						range = startQ + ' - ' + endQ;
					} else {
						range = startQ + '+';
					}

					return {
						price: price,
						range: range
					};
				});

				return processed;
			});


			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.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.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.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 && self.selectedUom().hasBreaks){
					if(oConfig.useBreaksTable && !oConfig.useUom && 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() {
				if (self.selectedProduct().uomPrice().length > 1) {
					return 'catalog.uom_select';
				} else {
					return 'catalog.uom_input';
				}
			});

			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.toLowerCase() === 'child'){
					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.useQtyRestrictions) {
					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.useQtyRestrictions) {
					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.useQtyRestrictions && self.selectedProduct().selectedUom().maxQty() > 0) {
					return self.selectedProduct().selectedUom().maxQty();
				} else {
					return '';
				}
			});

			self.hasQuantityRestrictions = ko.computed(function () {
				return !!(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.useAliases){
					return 'product_history_detail.asp?search2=searchexact~p.sku~' + parent.sku() + '&s=' + parent.sku()
				}else{
					return 'product_history_detail.asp?search2=searchexact~pa.sku_alias~' + parent.sku() + '&s=' + parent.sku()
				}
			};

			self.getSmartListLinkInvoiceStats = function(parent){
				if(!parent){
					return 'products_invoiced_detail.asp'
				}
				if(!oConfig.detailConfig.useAliases){
					return 'products_invoiced_detail.asp?search2=searchexact~p.sku~' + parent.sku() + '&s=' + parent.sku()
				}else{
					return 'products_invoiced_detail.asp?search2=searchexact~pa.sku_alias~' + 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(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
					},
					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();

							self.selectedProduct(self);
							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);
								}
							}
						});
						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
					},
					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);
					},
					error: function() {
						utils.popToastrError('Error Loading Product', 'There was an error loading the product');
					},
					complete: callback
				});
			}

			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
						},
						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') {
					// Functionality changed between 3.10 and 4.10, new name to not break other things
					_.uniqBySpecial = _.uniqBy || _.uniq;

					var rowOpt = '';
					var colOpt = '';
					var swatchOpt = "color_code";

					// Get sorted, unique row and column values, so that we can form the matrix
					var prodRows = _.map(_.sortBy(_.uniqBySpecial(self.children(), rowOpt), rowOpt + '_sort'), rowOpt);
					var prodCols = _.map(_.sortBy(_.uniqBySpecial(self.children(), colOpt), colOpt + '_sort'), colOpt);

					// Make this easily accessible by hooks
					var hookInfo = {
						rowOpt: rowOpt,
						colOpt: colOpt,
						swatchOpt: swatchOpt,
						prodRows: prodRows,
						prodCols: prodCols
					}

					// Construct the matrix, one row at a time
					var matrix = _.map(prodRows, function(rowLabel) {
						// Set defaults
						var swatch = '';
						var thumb = 'images/no-image.png';

						// Set the swatch
						var swatchProd = _.find(self.children(), function(child) {
							return (child[rowOpt] == rowLabel) && child[swatchOpt];
						});
						if (swatchProd) {
							swatch = swatchProd[swatchOpt];
						}

						// Set the thumbnail image
						var thumbProd = _.find(self.children(), function(child) {
							return (child[rowOpt] == rowLabel) && child.thumb && child.thumb() && child.thumb() != 'images/no-image.png';
						});
						if (thumbProd) {
							thumb = thumbProd.thumb();
						}

						// Generate the columns
						var cols = _.map(prodCols, function(colLabel) {
							// Find the product that sits at the intersection of row and col
							var currentProduct = _.find(self.children(), function(child) {
								return (child[rowOpt] == rowLabel && child[colOpt] == colLabel);
							});

							var col = {
								label: colLabel,
								product: currentProduct
							};

							runHook('productDetailMatrixCol', {
								parent: self,
								info: hookInfo,
								col: col
							});

							return col;
						});

						// Return the results
						var row = {
							label: rowLabel,
							swatch: swatch,
							thumb: ko.observable(thumb),
							cols: cols
						};

						runHook('productDetailMatrixRow', {
							parent: self,
							info: hookInfo,
							row: row
						});

						return row;
					});

					runHook('productDetailMatrixData', {
						parent: self,
						info: hookInfo,
						matrix: matrix
					});

					return matrix;
				} else {
					return [];
				}
			}).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') {

				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.matrixColors = ko.observable(product.matrixColors);

			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'
			];

			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())
				}

				if(!self.tabs || !self.tabs.length) {
					self.tabs = self.currentParent().tabs;
				}
			}


			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.changeSort = function (value) {
				window.location = utils.setParameter('sortby', value );
			};

			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 property="itemListElement" typeof="ListItem" data-bind="css: { active: !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 property="itemListElement" typeof="ListItem" data-bind="css: { active: !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>
					<!-- ko if: !oConfig.fastTrack -->
						<span data-bind="template: { name: 'catalog.additional_sections', data: mainProduct }"></span>
					<!-- /ko -->
				</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 well well-small 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">
		<!-- template: { name: 'catalog.breadcrumbs', data: breadcrumbs } -->
		<!-- ko if: pic -->
			<div class="head_thumb">
					<img data-bind="attr: { src: utils.buildImagePath(pic) }"/>
			</div>
		<!-- /ko -->
		<h1 class="head_title" data-bind="html: name"></h1>
		<!-- ko if: !oConfig.fastTrack && description -->
			<div class="head_desc" data-bind="html: description"></div>
		<!-- /ko -->
		<!-- template: { name: 'catalog.category_list', data: children, if: children.length > 0 } -->
	</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.fastTrack && pic2">
					<a data-bind="attr: { href: link, title: utils.decodeHTML(name), 'data-key': key }">
						<img data-bind="attr: { src: utils.buildImagePath(pic2), alt: utils.decodeHTML(name) }"/>
					</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.pageType != 'category' && oConfig.searchConfig.pageType != 'favlist' -->
			<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
					">
			</h1>
		<!-- /ko -->
		<!-- ko if: oConfig.searchConfig.pageType == 'favlist' -->
			<h1 data-bind="text: decodeURIComponent(utils.getParameter('nm'))"></h1>
		<!-- /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">
			<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"
				></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"
				></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 != 'category' && oConfig.searchConfig.pageType != 'favlist' -->
			<!-- 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 are using 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>
			<div data-bind="template: 'catalog.list_view_atc'"></div>
		</form>
	</script>

	<script type="text/html" id="catalog.list_view_atc">
		<div data-bind="if: oConfig.searchConfig.showAtc && showAddAllToCart() && !oConfig.showListViewATC">
			<span id="btn_multi_add_to_cart_anchor"></span>
			<div id="btn_multi_add_to_cart" class="container-fluid" data-bind="sticky: 'btn_multi_add_to_cart_anchor'">
				<div data-bind="attr: { class: oConfig.searchConfig.gridListViewRowClass }">
					<div data-bind="attr: { class: oConfig.searchConfig.gridListViewATCColumnClass }">
						<div class="form-actions">
							<button type="button"
								class="btn btn-block btn-primary btn-large"
								data-bind="
									html: utils.atcListButtonText(),
									click: function(data,event) {addToCartWithValidation(results(), event);}">
							</button>
						</div>
					</div>
				</div>
			</div>
		</div>
	</script>

<script type="text/html" id="catalog.product_card_with_children">
	<!-- template: 'catalog.product_card' -->
</script>


<script type="text/html" id="catalog.product_card_no_children">
	<!-- template: 'catalog.product_card' -->
</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.fastTrack, 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">
						<!-- template: 'catalog.name_link' -->
					</div>
					<!-- template: 'catalog.rating_score' -->
				</div>
				<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 class="prod-details">
					<!-- template: { name: 'catalog.detail_info' } -->
				</div>
				<!-- ko if: utils.getParameter('favorites') && oConfig.pageName == 'pc_combined_results.asp' -->
					<!-- template: 'catalog.remove_fav_button' -->
				<!-- /ko -->
			</div>
		<!-- /ko -->
		<!-- ko if: isActiveLayout('list') -->
			<div class="prod-thumb" data-bind="visible: !oConfig.fastTrack, 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">
						<!-- template: 'catalog.name_link' -->
					</div>
					<div class="prod-ds" data-bind="
						html: selectedProduct().description, 
						visible: !oConfig.fastTrack && oConfig.searchConfig.showDescription && selectedProduct().description()">
					</div>
					<!-- template: 'catalog.rating_score' -->
					<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' -->
				<!-- template: 'catalog.remove_fav_button' -->
			<!-- /ko -->
		<!-- /ko -->
	</div>
</script>

<script type="text/html" id="catalog.advanced_parent_layout">
	<!-- template: { name: "catalog.product_title", data: selectedProduct } -->
	<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: 'Item 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-large btn-primary scroll-to" 
				 data-bind="
				   attr: { href: '#input-qty' }, 
					 html : oConfig.detailConfig.labels.inputQtyATCLabel, 
					 click: function() {
						 scrollToTarget($element);
						 return false;
					 }
				">
			</a>
		</div>
	</div>
	<!-- template: 'catalog.additional_info' -->
	<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">
		<!-- template: 'catalog.matrix_table' -->

		<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);
					},
					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>
				<!-- template: { name: 'catalog.matrix_prod', data: product} -->
			<!-- /ko -->
			
			<!-- ko ifnot: product -->
				<!-- template: 'catalog.matrix_prod_not_found' -->
			<!-- /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">
		<!-- template: 'catalog.input_qty_table' -->
		<!-- 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: hasCartOptions() && !oConfig.fastTrack -->
	<ul class="unstyled" data-bind="foreach: questions">
		<li class="form-inline" data-bind="template: { name: 'catalog.cart_option_' + type() }"></li>
	</ul>
	<!-- /ko -->
	<!-- ko if: !hasCartOptions() && !oConfig.fastTrack  -->
		<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" >
		<!-- template: 'catalog.add_row_table' -->
		<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-medium btn-success" data-bind="click: function () { addRows(1) }"><i class="icon-add"></i> Add Row</button>
			<button class="btn btn-medium btn-success" data-bind="click: function () { addRows(5) }"><i class="icon-add"></i> Add 5 Rows</button>
			<button class="btn btn-medium btn-default pull-right" data-bind="click: addRowsToCart"><i class="icon-add"></i> 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">
			<thead>
				<tr>
					<th>Option</th>
					<!-- ko fastForEach: tableColumns -->
					<th data-bind="
							text: 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">
								<!-- 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">
			<thead>
				<tr data-bind="fastForEach: tableColumns">
					<th data-bind="
							text: 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="
								template: {name: template, data: ko.unwrap($parent) }, 
								css: ko.unwrap($data).cellClass
							">
						</td>
					<!-- /ko -->

					<!-- ko if: !$data.template -->
						<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>
		<!-- template: 'catalog.product_links' -->
	</div>
</script>

<script type="text/html" id="catalog.product_view">
	<!-- template: { name: "catalog.product_title", data: selectedProduct } -->
	<div id="product_view" class="row-fluid product_view">
		<div data-bind="attr: { class: oConfig.detailConfig.gridLeftColumnClass + ' product-detail__left' }">
			<!-- ko if: oConfig.fastTrack -->
				<!-- ko template: 'catalog.detail_info_container' --><!-- /ko -->
			<!-- /ko -->
			<!-- ko if: !oConfig.fastTrack -->
				<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.fastTrack -->
				<span data-bind="template: { name: 'catalog.smart_lists', data: selectedProduct() }"></span>
			<!-- /ko -->
			<!-- ko if: !oConfig.fastTrack -->
				<!-- ko template: 'catalog.detail_info_container' --><!-- /ko -->
			<!-- /ko -->
		</div>
	</div>
	<!-- template: 'catalog.additional_info' -->
</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: 'Item on Promotion',
					descriptions: promoDescriptions,
					selectedProduct: selectedProduct
				}
			}
		">
		</div>
		<!-- ko if: oConfig.detailConfig.showProductDescriptionTop && !oConfig.fastTrack -->
			<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>
		<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="text: 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 }" >
		<!-- template: 'catalog.advanced_tabs' -->
	</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.showProductDescriptionTop && !oConfig.fastTrack -->
			<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>
		<span data-bind="template: { name: 'catalog.smart_lists', data: selectedProduct() }"></span>
	</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>
				<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">
	<!-- template: { name: 'catalog.reviews', data: mainProduct } -->
</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">
	<!-- template: { name: 'catalog.product_facets_table', data: mainProduct.selectedProduct() } -->
</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 -->
				<!-- template: { name: 'catalog.reviews_list', data: reviews } -->
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.reviews_list">
		<div class="media-list reviews-list">
			<!-- template: { name: 'catalog.review', if: size, foreach: items } -->
		</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>
			<!-- template: { name: 'catalog.review', if: children, foreach: children } -->
		</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">
				<!-- template: 'catalog.rating_score' -->
				<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 -->
			<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 }"
						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()) selectedQty(minQty() || 1); },
						attr: {
							'min' : minQty()  || 1,
							'step': stepQty() || 1,
							'max' : maxQty()
						},
						visible: !isChild() || oConfig.allowChildATC,
						validateQty
					"
					type="number"
					pattern="\d*"
					class="qty-input"
					placeholder="Qty"
					aria-label="Qty"
				>
				<!-- template: {name: 'catalog.product_actions_add', if: selectedProduct().childDisplayType() !== 'matrix-all'} -->
			</div>
			<div class="text-error" data-bind="visible: !questionsHaveValidAnswers() && currentParent().rowsAtcAttempted()">Please ensure all required fields are populated.</div>
		<!-- /ko -->

		<!-- ko ifnot: selectedProduct().showQuickAtc -->
			<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 -->
	</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 -->
			<!-- ko if: (currentParent().childDisplayType() == 'add-row') -->
				<button type="button" class="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 -->
		</div>
	</script>

	<script type="text/html" id="catalog.atc_full">
		<!-- ko ifnot: $data.type === 'parent' -->
			<!-- ko if: oConfig.useIdp -->
				<!-- template: 'catalog.inventory' -->
			<!-- /ko -->
			<fieldset id="cart_options" data-bind="visible: selectedProduct().hasCartOptions() && !oConfig.fastTrack">
			<legend>Additional Options</legend>
				<!-- ko template: { name: 'catalog.cart_options', data: selectedProduct, if: selectedProduct().questions().length > 0 } --><!-- /ko -->
			</fieldset>
			<!-- template: 'catalog.configurator' -->
			<!-- ko if: oConfig.UseTaxExempt -->
				<!-- template: 'catalog.tax_exempt' -->
			<!-- /ko -->
		<!-- /ko -->
		<!-- ko if: $data.isDangerous -->
			<!-- template: 'catalog.hazmat' -->
		<!-- /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 -->
			<!-- template: { name: 'catalog.atc_form_submit', data: selectedProduct } -->
		<!-- /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':  minQty()  || stepQty() || 1,
							'step': stepQty() || 1,
							'max' : maxQty()  || ''
						},
						validateQty
					"
					onclick="this.focus();this.select();"
					type="number"
					pattern="\d*"
					class="qty-input product-detail__qty-input"
				>
			</div>
			<div data-bind="template: { name: 'catalog.qty_restrictions', if: oConfig.useQtyRestrictions }"></div>
		</div>
	</script>

	<script type="text/html" id="catalog.atc_form_submit">
		<div class="media 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 btn-large button 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>
	</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">item</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: utils.decodeHTML(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">
		<!-- template: 'catalog.atc_popup' -->
		<!-- 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="invalid-qty" data-bind="text: oConfig.labels.invalidQtyText"></div>
	</script>

	<script type="text/html" id="catalog.saved_cart_select_popup">
		<!-- 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>
			<!-- template: 'catalog.saved_carts_table'-->
		<!-- /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 -->
	</script>

	<script type="text/html" id="catalog.saved_carts_table">
		<!-- ko if: savedCarts.length -->
			<table class="table" data-bind="if: savedCarts.length > 0">
				<tbody data-bind="foreach: { data: savedCarts, as: 'cart' }">
					<tr><td>
						<a
							class="btn btn-block btn-link text-left"
							href="#"
							data-bind="
								click: function () {
									$parent.selectedCart(cart);
								},
								spacedtext: cart.nickname || cart.refId
							"
						></a>
					</td></tr>
				</tbody>
			</table>
		<!-- /ko -->
		<!-- ko ifnot: savedCarts.length -->
			<div>
				<h6>None Found</h6>
			</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="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>
			<div class="cart-sc-nm" data-bind="text: cart.nickname"></div>
			<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="my_saved_carts.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>
	</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: 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: 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: 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()">
			<a data-bind="attr: { href: 'pricebreakpopup.asp?p_key=' + key() }, text: oConfig.labels.breaks" class="global-modal" data-size="small"></a><br>
		</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: showPrice && processedBreaks().length">
			<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">
					<tr>
						<td data-bind="text: range"></td>
						<td data-bind="text: utils.formatPrice(price)"></td>
					</tr>
				</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.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">
				<!-- template: 'catalog.product_card' -->
			</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){
				var quantity = item.qty_available();
				var message = '';

				if($data.inventory.inventoryStatus() == 'in'){
					if(quantity >= 0 || !$.isNumeric(quantity)){
						message = quantity + ' ';
					}else{
						message = '0 ';
					}
				}

				if($data.inventory.showMessage){
					message = message + utils.removeHTML($data.inventory.stockMessage());
				}

				if(message !== ''){
					message = '(' + message + ')';
				}
				return item.name() + ' ' + message;
			},
			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: qty_available()"></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 : selectedWarehouse().qty_available()
				"></span>
			</div>
			<input type="hidden" data-bind="
				attr : {
					'id' : selectedWarehouse().key,
					'name' : selectedWarehouse().key,
					'value' : selectedWarehouse().key
				}
			">
		</div>
	</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(name) }, 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: utils.decodeHTML(thumbAltText() || $parent.thumbAltText() || name() || $parent.name()),
					title: utils.decodeHTML(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: utils.decodeHTML(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 -->
				<!-- template: 'catalog.email_friend' -->
			<!-- /ko -->
			<!-- ko if: oConfig.showFavLink -->
				<!-- template: 'catalog.fav_button' -->
			<!-- /ko -->
			<!-- ko if: oConfig.showRFQLink -->
				<!-- template: 'catalog.rfq_button' -->
			<!-- /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 --'
				"
			></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?p_id=' + key() + '&type=product' }"
			 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">
		<span data-bind="text: oConfig.labels.hazmat"></span><br>
		<!-- ko if: dangerousRatio() !== 1 -->
			<span data-bind="html: oConfig.labels.hazmatBoxRatio + dangerousRatio()"></span><br>
		<!-- /ko -->
		<!-- ko if: oConfig.hazmatLink-->
			<a class="global-modal" data-bind="text: oConfig.labels.hazmatHelpText, attr: { href: oConfig.hazmatLink }"></a> <br>
		<!-- /ko -->
	</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>
						<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">
		<!-- if: oConfig.fastTrack && oConfig.showProductHistory && oConfig.isLoggedIn-->
			<div class="smart-lists-container" >
				<div class="smart-list">
					<!-- ko if: isOrdered-->
						<div class="list-group-item total-qty-ordered">
							Total Qty Ordered
							<span class="pull-right" data-bind="text: sumQty"></span>
						</div>
						<div class="list-group-item total-times-ordered">
							Total Times Ordered
							<span class="pull-right" data-bind="text: orderCount"></span>
						</div>
						<div class="list-group-item most-recent-order-date">
							Most Recent Order
							<span class="pull-right" data-bind="text: mostRecentOrderDate"></span>
						</div>
					<!-- /ko -->
				</div>
			
		<!-- /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="smart-lists-container">
				<div class="smart-list">
					<!-- ko ifnot: accountHistory -->
						<p class="alert alert-warning">No additional information available.</p>
					<!-- /ko -->
					<!-- ko if: accountHistory -->
						<div class="well well-small clearfix smart-list-meta">
							<div class="pull-left" data-bind="if: accountHistory.accountName">
								<strong>Account:</strong>
								<!-- text: accountHistory.accountName -->
							</div>
							<div class="pull-right" data-bind="if: accountHistory.lastUpdate">
								<strong>Last Updated:</strong>
								<!-- text: accountHistory.lastUpdate -->
							</div>
						</div>
						<!-- template: { name: 'catalog.smart_lists_panels', data: accountHistory, if: accountHistory } -->
					<!-- /ko -->
				</div>
			</div>
		<!-- /ko -->
	</script>

	<script type="text/html" id="catalog.smart_lists_panels">
		<div class="row-fluid">

			<div class="span4">
				<div class="panel panel-default order-stats">
					<div class="panel-heading">
						<div class="panel-title">Order Stats</div>
					</div>
					<div class="list-group">
						<!-- ko if: isOrdered -->
							<div class="list-group-item total-qty-ordered">
								Total Qty Ordered
								<span class="pull-right" data-bind="text: sumQty"></span>
							</div>
							<div class="list-group-item total-times-ordered">
								Total Times Ordered
								<span class="pull-right" data-bind="text: orderCount"></span>
							</div>
							<div class="list-group-item most-recent-order-date">
								Most Recent Order
								<span class="pull-right" data-bind="text: mostRecentOrderDate"></span>
							</div>
							<div class="list-group-item oldest-order-date">
								Oldest Order
								<span class="pull-right" data-bind="text: oldestOrderDate"></span>
							</div>
							<a class="list-group-item text-center" data-bind="attr: { href: $parent.getSmartListLinkOrderStats($parent) }">
								View Details <i class="icon-angle-right"></i>
							</a>
						<!-- /ko -->
						<!-- ko ifnot: isOrdered -->
							<div class="list-group-item previously-ordered">
								Previously Ordered
								<span class="pull-right">No</span>
							</div>
						<!-- /ko -->
					</div>
				</div>
			</div>

			<div class="span4">
				<div class="panel panel-default invoice-stats">
					<div class="panel-heading">
						<div class="panel-title">Invoice Stats</div>
					</div>
					<div class="list-group">
						<!-- ko if: isInvoiced -->
							<div class="list-group-item total-qty-invoiced">
								Total Qty Invoiced
								<span class="pull-right" data-bind="text: sumInvoiceQty"></span>
							</div>
							<div class="list-group-item total-times-invoiced">
								Total Times Invoiced
								<span class="pull-right" data-bind="text: invoiceCount"></span>
							</div>
							<div class="list-group-item most-recent-invoice-date">
								Most Recent Invoice
								<span class="pull-right" data-bind="text: mostRecentInvoiceDate"></span>
							</div>
							<div class="list-group-item oldest-invoice-date">
								Oldest Invoice
								<span class="pull-right" data-bind="text: oldestInvoiceDate"></span>
							</div>
							<div class="list-group-item amount-invoiced-mtd">
								Invoiced MTD
								<span class="pull-right" data-bind="html: utils.formatMoney(sumInvoicedMtd)"></span>
							</div>
							<div class="list-group-item amount-invoiced-last-month">
								Invoiced Last Month
								<span class="pull-right" data-bind="html: utils.formatMoney(sumInvoicedLastMonth)"></span>
							</div>
							<div class="list-group-item amount-invoiced-ytd">
								Invoiced YTD
								<span class="pull-right" data-bind="html: utils.formatMoney(sumInvoicedYtd)"></span>
							</div>
							<div class="list-group-item amount-invoiced-last-year">
								Invoiced Last Year
								<span class="pull-right" data-bind="html: utils.formatMoney(sumInvoicedLastYear)"></span>
							</div>
							<div class="list-group-item total-amount-invoiced">
								Total Invoiced
								<span class="pull-right" data-bind="html: utils.formatMoney(sumInvoiced)"></span>
							</div>
							<a class="list-group-item text-center" data-bind="attr: { href: $parent.getSmartListLinkInvoiceStats($parent) }">
								View Details <i class="icon-angle-right"></i>
							</a>
						<!-- /ko -->
						<!-- ko ifnot: isInvoiced -->
							<div class="list-group-item previously-invoiced">
								Previously Invoiced
								<span class="pull-right">No</span>
							</div>
						<!-- /ko -->
					</div>
				</div>
			</div>

			<div class="span4">
				<div class="panel panel-default other-stats">
					<div class="panel-heading">
						<div class="panel-title">Other Stats</div>
					</div>
					<div class="list-group">
						<!-- ko if: viewedCount -->
							<div class="list-group-item times-viewed">
								Times Viewed
								<span class="pull-right" data-bind="text: viewedCount"></span>
							</div>
							<div class="list-group-item most-recent-view-date">
								Most Recent View
								<span class="pull-right" data-bind="text: mostRecentViewDate"></span>
							</div>
						<!-- /ko -->
						<div data-bind="visible: oConfig.smartListShowFavorites" class="list-group-item on-favorites-list">
							<span data-bind="html: oConfig.smartListFavoritesText"></span>
							<span class="pull-right" data-bind="text: isOnFavList ? 'Yes' : 'No'"></span>
						</div>
						<div data-bind="visible: oConfig.smartListShowInventoryWatch" class="list-group-item on-inventory-watch">
							<span data-bind="html: oConfig.smartListInventoryWatchText"></span>
							<span class="pull-right" data-bind="text: isOnInventoryWatch ? 'Yes' : 'No'"></span>
						</div>
						<div data-bind="visible: oConfig.smartListShowAbandonedCart" class="list-group-item in-abandoned-cart">
							<span data-bind="html: oConfig.smartListAbandonedCartText"></span>
							<span class="pull-right" data-bind="text: isInAbandondedCart ? 'Yes' : 'No'"></span>
						</div>
					</div>
				</div>
			</div>

		</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: isInAbandondedCart ? 'Yes' : 'No'"></td>
			</tr>
		</table>
	</script>

	<script type="text/html" id="catalog.detail_info">
		<dl class="prod-searchfields">
			<!-- template: 'catalog.sku_label' -->
			<!-- template: { name: 'catalog.searchfields', foreach: _.values(selectedProduct().searchfields) } -->
		</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.fastTrack && 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});
			}
		};

		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;
					}

				});
			}
		};

		(function () {
			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 () {
						console.log($(this));
						price += $(this).data('price') || 0;
					});

				return price;
			}

			window.buildConfiguratorPriceObservable = function (productKey) {
				var priceObservable = ko.observable(0);
				var $inputs = getInputs(productKey);

				if ($inputs) {
					priceObservable(getPrice($inputs));

					$inputs.change(function () {
						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>

	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) {
		window.location = utils.setParameter('sortby', event.target.value );
	}

	function getSelectedSort() {
		return decodeURI(utils.getParameter('sortby')) || 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() {
		return oConfig.pageName === 'pc_combined_results.asp' ? oConfig.searchConfig.showLayout ? utils.getCookie('productLayout') || oConfig.searchConfig.layout : oConfig.searchConfig.layout : null;
	}

	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.' + (utils.getCookie('productLayout') || 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 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
			);
			ko.applyBindingsToNode(optionElement, {disable: obs}, item);
		}
	}

	function addToCartWithValidation(products, event, parentKey) {
		var invalidQtyIndex = _.findIndex(products, function(product) {return !product.isQtyValid()});

		//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>', "Cart");
	}

	$(function () {
		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: 'templates/gfx/',
						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;
		}
		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(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&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 = "pc_combined_results.asp";
	var breadcrumbKey = "";
	var breadcrumbObj = utils.getStoredBreadcrumbs() || {breadcrumbs:{}};
	var activeBreadcrumb = breadcrumbObj.breadcrumbs[breadcrumbKey];
	
		$(function() {
			if(pageType == 'category' && !activeBreadcrumb){
				//no breadcrumb, add one
				var categoryName = $('#category-window li.active a').first().text();
				var categoryLink = $('#category-window li.active a').first().attr('href');
				categoryBreadcrumb = [];
				$('#detail_breadcrumbs li').each(function(){
					if(categoryName != $($(this).children()).text()) {
						categoryLink = $($(this).children()).attr('href') || categoryLink
					}
					categoryBreadcrumb.push({ name: $($(this).children()).text(), link: categoryLink } );
				});
				breadcrumbObj.breadcrumbs[breadcrumbKey] = categoryBreadcrumb;
				utils.setStoredBreadcrumbs(breadcrumbObj);
				activeBreadcrumb = breadcrumbObj.breadcrumbs[breadcrumbKey];
			}
		});

		$(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'){
				defaultBreadcrumb = [{ name: 'Search Results', 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: "" || "" || "" || "",
		activeBreadcrumb: activeBreadcrumb,
		t_analytics                         : "none",
		t_tracking_company                  : "",
		t_tracking_id                       : "",
		t_gtm                               : false,
		t_gtm_id                            : "",
		sessionData : {
			sc_id : "4A0D68FD60E4491F97A573CF9A0CA909",
			sessionKey : "23CC993A1E514976B551384C0DC27E3F",
			storefrontUrl : "https://sbshutter.cimproduction.com",
			orderfrontUrl : "https://sbshutter.cimproduction.com",
			cdnUrl: "https://d370ry6d2q1pi0.cloudfront.net",
			isSuperUserSession : false
		},

		detailConfig : {
			productKey                 : '',
			useAdvancedTabs            : true,
			useRelatedProducts         : true,
			useSecondRelatedProducts   : true,
			useAlsoBoughtProducts      : false,
			useRecentlyViewedProducts  : true,
			useAliases                 : true,
			selectChildProductOnLoad   : true,
			tabLayoutMode              : "list",
			pageLayoutMode             : "gallery",
			showDocuments              : true,
			inputQtyLinkToChild        : false,
			globalUnitPriceDecimalPlaces : 2,
			gridRowClass               : "",
			gridLeftColumnClass        : "",
			gridRightColumnClass       : "",
			showProductDescriptionTop  : false,
			showSoftGoodAuthorizations : false,
			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-chevron-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)"
	},{
		"field"     : "ISNULL(pah.sum_order_qty, 0)",
		"direction" : "desc",
		"display"   : "Total Qty Ordered"
	},{
		"field"     : "pah.ordered",
		"direction" : "desc",
		"display"   : "Total Times Ordered"
	},{
		"field"     : "pah.most_recent_date_ordered",
		"direction" : "desc",
		"display"   : "Most Recent Ordered"
	}],
			showDownload               : false,
			gridListViewRowClass       : "",
			gridListViewATCColumnClass : "",
			showDescription            : true,

			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://sbshutter.cimproduction.com/i_i_add_to_cart.asp",
		isLoggedIn : false,
		showChildrenSelection: false,

		usePromos                : false,
		useIdp                   : false,
		useUom                   : (true || false),
		useMultiUomMultiCurrency : false,
		useQtyRestrictions       : true,
		useReviews               : false,
		allowAddAnonymousReviews : false,
		get allowAddReviews()
			{
				return this.isLoggedIn || this.allowAddAnonymousReviews;
			},
		useBreaks                : true,
		useBreaksTable           : true,
		priceBreaksTableHeader   : "Quantity Price Breaks",
		useSavedCarts            : false,
		useTaxExempt             : false,
		showInventoryWatch       : false,
		showEmailFriend          : false,
		showFavLink              : true,
		showRFQLink              : false,
		showProductHistory		 : true,
		showProductHistoryResults: true,
		showWarehouses           : false,
		showProdYouSave          : true,
		allowWarehouseSelection  : false,
		useWarehousesTable       : false,
		defaultWarehouse         : "",
		hazmatLink               : "",
		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.",
		fastTrack                : false,
		showPricingOrderEntry    : true,
		configuratorUseAnswerIdNotName: 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                           : "Hazardous Material",
			hazmatBoxRatio                   : "Box Ratio",
			hazmatHelpText                   : "What's This?",
			softgoods						 : "Purchasing this item provides a digital file that will be delivered upon placing the order.",
			invalidQtyText                   : "Please enter a valid quantity greater than 1",
			invalidQtyTitle                  : "Invalid Quantity",
			youSaveLabel                     : "You Save",
			removeFavLink                    : "Remove From Favorites",
			rfqLinkLabel                     : "Request a Custom Quote",

			savedCarts			: "Cart",
			savedCartsLabels 	: {
				addToSavedCart                   : replaceSavedCartKeywordWithGlobal("Add to <cart>"),
				itemText	                     : replaceSavedCartKeywordWithGlobal("Item"),
				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"
		},

		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            : true,
		smartListInventoryWatchText            : "On Inventory Watch?",
		smartListShowAbandonedCart             : true,
		smartListAbandonedCartText             : "In Abandoned Cart?",
		t_analytics                            : "none",
		t_tracking_company             		   : "",
		t_tracking_id                          : "",
		t_gtm                                  : false,
		t_gtm_id                               : "",
		t_gtm_add_to_cart_event_name           : ""
	};

	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">

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 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.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) {
            utils.setCookie('activequote', orderKey);
        }
    }
    
    utils.removeActiveQuote = function (bStartNewQuote) {
        utils.setCookie('activequote', '');
        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 countries = [];
    var newCustomer = false;
    var viewModel;
    var order;

    function addAddressHandler() {
        viewModel.allocateShipments(false);
        apiGetShippingAddresses();

    }

    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.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.country(newItem.zipCode());
                                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",
            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();
        }

        if(!addressData.global){
            addressData.global = '1';
        }

        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()) {
                    if(item.orderDetail.parentProductID().trim() != '' && item.orderDetail.removeType() != 'instance') {
                        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.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().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().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('');
        };

        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()
                },
                "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 ship via');
                }
            }

            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) {

            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) {
        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({});
                    } 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'){
                        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) {
            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.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 items to shipment');
                },
                complete: function() {
                    self.processing(false);
                }
            }

            postInfo(postOptions, 'updateShipToAddress');

            $('#modal_add_prods[tabindex="-1"]:hidden').remove()
            $('#modal_add_prods').modal('hide');
        };

        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 2 if any shipments are missing an address.
            _.each(self.shipments(),function(shipment){
                if(!shipment.shipTo().key()){
                    return false;
                }
            });

            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;
            _.each(self.itemShipToMap(), 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.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 saving shipping address');
                }
            }

            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.toggleSuperUserMode = function(){
            viewModel.superUserOrderFormMode(!viewModel.superUserOrderFormMode());
            var postOptions = {
                data: {
                    superUserMode: viewModel.superUserOrderFormMode()
                },
                success: function(data) {
                    //
                },
                error: function() {
                    alert('error reloading shipping accounts');
                }
            }

            postInfo(postOptions, 'setSuperUserMode');
        };

        self.returnToPendingOrders = function() {
            window.location = 'su_pending_orders_man.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.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: []
                };

                //Loop the unique products and sum the quantities before adding them back to the shipment.
                // EJ - I _think_ this loops and sums by instance so that previously split instances will end up
                // with the correct qty instead of the last item in that instance.  This however breaks
                // when configurator products are in the cart that contain more than one distinct product
                // in the instance.
                _.sortBy(viewModel.itemShipToMap(),'instance').forEach(function(map){
                    shipmentInfo.Details.push( {
                        OrderDetailId:  map.orderDetailKey,
                        QtyToShip: viewModel.getOrderDetailQty(map.instance())
                    });
                });
                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?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 item list on shipment');
                }
            }

            postInfo(postOptions, 'updateShipToAddress');
            if(moveToNextStep === undefined) {
                moveToNextStep=true;
            }
            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_container');
                    }else{
                        scrollToSection('#checkout_container');
                    }
                },
                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.showAddressBook = function(shipment) {
            self.currentShipment(shipment);
            getShippingAddresses();
            //$('#modal_addressbook')[0].remove();
            $('#modal_addressbook').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 ship via');
                },
                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", viewModel.poNumber());
        });

        self.comments.subscribe(function(newComments) {
            postOrderHeaderField("comment", viewModel.comments());
        });

        self.nickname.subscribe(function(nickname) {
            self.buildOrderHeaderFields(["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", viewModel.roRunDate());
        });    

        self.roRecCase.subscribe(function(roRecCase) {
            postOrderHeaderField("ro_rec_case", viewModel.roRecCase());
        });    

        self.roRecQty.subscribe(function(roRecQty) {
            postOrderHeaderField("ro_rec_qty", viewModel.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.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 minGrossMarginPercent = parseInt(detailLine.minGrossMarginPercent() || 0);
                        var val = parseInt(newVal);
                        if(val < minGrossMarginPercent()) {
                            val = minGrossMarginPercent();
                        }
                        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 minGrossMarginAmount = parseInt(detailLine.minGrossMarginAmount() || 0);
                        var val = parseInt(newVal);
                        if(val < minGrossMarginAmount()) {
                            val = minGrossMarginAmount();
                        }
                        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
                        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.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;
        });
        
        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.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()
                            });
                        }

                        dataLayer.push({ 'pageType' : 'confirmation' });
                        dataLayer.push({ 'orderNumber' : self.orderNumber() });
                        dataLayer.push({ 'storeName' : ofConfig.t_tracking_company });
                        dataLayer.push({ 'productTotal' : self.productTotal() });
                        dataLayer.push({ 'shippingTotal' : self.shippingTotal() });
                        dataLayer.push({ 'taxTotal' : self.taxTotal() });
                        dataLayer.push({ 'orderTotal' : self.orderTotal() });
                        dataLayer.push({ 'customerName' : self.customer.firstName() + ' ' + self.customer.lastName() });
                        dataLayer.push({ 'customerFirstname' : self.customer.firstName() });
                        dataLayer.push({ 'customerLastName' : self.customer.lastName() });
                        dataLayer.push({ 'customerCity' : self.account.city() });
                        dataLayer.push({ 'customerState' : self.account.state() });
                        dataLayer.push({ 'customerCountry' : self.account.country() });
                        dataLayer.push({ 'customerEmail' : self.customer.email() });
                        dataLayer.push({ 'couponCode' : self.couponCode() });
                        dataLayer.push({ 'couponAmount' : self.couponDiscountTotals.totalDiscount() });
                        dataLayer.push({ 'paymentMethod' : self.paymentMethod.name() });
                        dataLayer.push({ 'sessionIP' : ofConfig.SessionIP });
                        
                        // For Google Analytics (non-EE)
                        dataLayer.push({
                            'transactionId': self.orderNumber(),
                            'transactionAffiliation': ofConfig.t_tracking_company,
                            'transactionTotal': self.orderTotal(),
                            'transactionTax': self.taxTotal(),
                            'transactionShipping': self.shippingTotal(),
                            'transactionProducts': transactionProducts
                        });

                        // For Enhanced Ecommerce
                        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
                                }
                            }
                        });

                        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;
                }
            }
        }
        /* 
        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'); 
        }

        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(ofConfig.bAllowProductAdds || ofConfig.superUserAllowProductAdds);
                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() && ofConfig.bAllowProductAdds );
                self.allowQtyControls( false );
            }
        };

        self.updateOrderAccess();

        self.processOrderAction = 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;
                }
            }

            if(!bContinueProcessing){

                }else{

                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_container';
                
                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');
        };

        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();

                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.productFinderSearchTerm('');
                },
                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;
            }

/*
            // EJ - replaced the below if statement with the the code below to account for SU setting
            // all but one detail line on an order / quote to disallow delete.
            // I believe this was supposed to handle instanced items, but I'm not entirely certain
            // Leaving the code here in case I'm wrong
            if( _.filter(viewModel.detailLines(),function(detail) { return detail.removeType() != 'hide'} ).length == 1 ){
                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 = 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() + '<span class="divider"><i class="icon-chevron-right"></i></span></li>';
            } else {
                return '<ul class="breadcrumb breadcrumb-cart"><li class="active">' + ofConfig.SavedCartLabel + '# ' + self.referenceId() + '<span class="divider"><i class="icon-chevron-right"></i></span></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"]);
        });

        runHook('orderModelBottom', { self: self, order: self });
    } // end of var Order = blah blah blah

    //This code was running on other pages and causing errors.
    if('signin.asp' == 'payment.asp' && isExistingOrder){

        var shippingAddresses = processShippingAddresses([]);

        if(shippingAddresses().length < 1){
            //redirect to bill-ship because the user has no shipping addresses
            var sUrl = 'account.asp?from=ct&err=no-shiptos&o_key=' + utils.getParameter('o_key') + (ofConfig.isModal ? '&modal=1' : '');
            document.location = sUrl;
        }
    }

    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.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) {

        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 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;

        if(!ajaxOptions.url) {
            ajaxOptions.url = orderInfoPostUrl + '?o_key=' + viewModel.orderKey() + '&ajax=true&pageaction=' + pageAction;
        }

        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(typeof existingSuccess === 'function') {
                existingSuccess(data);
            }

            if(scrollToId) {
                model.showConfirmationMessage(true);
                scrollToSection('#' + scrollToId);
            }
        };

        ajaxOptions.error = function(data) {
            if(typeof existingError === 'function') {
                existingError(data);
            }
        };

        ajaxOptions.complete = function() {
            runHook('postInfoAjaxCompleteFunction', { model: model });
            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, '');
    }

    $(function() {
        if(getOriginalPageName() !== 'bulk_atc.asp') {
            addGlobalModalCompletionHandler($('#find_product'), addFromProductFinder);
        }
    });
</script>
<script type="text/javascript">
    function handleSkuSubmission(sku, state) {
        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 {
                    var productInfo = {
                        productKey: requests[0].product.p_key,
                        productSku: requests[0].product.sku,
                        parentChildType: requests[0].product.parent_child_type,
                        parentProductId: requests[0].product.parent_p_id || ''
                    };
                    viewModel.loadProductForEdit(productInfo, '');
                }
            })
            .fail(_.bindKey(def, 'reject'));

        return def.promise();
    }

    function loadProductsByAjax(pageaction, prop, requests) {
        var def;

        if (requests.length) {
            def = $.Deferred();

            $.ajax({
                url: 'bulk_atc.asp?modal=1',
                dataType: 'JSON',
                data: {
                    pageaction: pageaction,
                    items: _.pluck(requests, prop)
                }
            })
                .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) {
        var $btn = $('#find_product');

        // Trigger the global modal handler.
        $btn.click();
    }

    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) {
			return self.key ? product.p_key === self.key : product.sku.toLowerCase() === self.sku.toLowerCase();
		};

		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) {
        return $.ajax({
            url: 'bulk_atc.asp',
            dataType: 'JSON',
            data: {
                pageaction: 'sku_list',
                prefix: prefix
            }
        })
        .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 data-bind="css: { hide: viewModel.completed() }, html: viewModel.breadcrumbMarkup"></div>
    <!-- ko template: { name: 'cart.confirmation'} --><!-- /ko -->
    <div id="checkout_billing" class="checkout-section active completed" data-bind="with: viewModel">
        <div class="checkout-section-heading">
            <h3 class="checkout-section-heading__text">Billing <i class="icon-ok-sign text-success" data-bind="visible: viewModel.billingSectionValid"></i></h3>
        </div>
        <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">
    <div class="print-hide" data-bind="if: viewModel.completed()">
        <button type="button" class="btn btn-primary pull-right" onclick="window.print();">
            <i class="icon-print"></i> Print
        </button>
    </div>
</script>

<script type="text/html" id="cart.superUserOrderFormButton">
    <!-- ko if: ofConfig.isSuperUserSession && ofConfig.superUserShowViewModeButton -->
        <button type="button" class="btn btn-secondary pull-right" data-bind="click: viewModel.toggleSuperUserMode">
            View as <span data-bind="if: viewModel.superUserOrderFormMode()">Normal User</span><span data-bind="ifnot: viewModel.superUserOrderFormMode()">Super User</span>
        </button>
    <!-- /ko -->
    <!-- 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-heading">
           <h3 class="checkout-section-heading__text">Items &amp; Shipping <i class="icon-ok-sign text-success" data-bind="visible: viewModel.shippingComplete"></i></h3>
           <button
                type="button"
                class="btn checkout-btn-edit pull-right"
                data-target="checkout_shipping"
                data-bind="
                    click:
                        function() {
                            viewModel.shippingComplete(false)
                        },
                    visible: viewModel.shippingComplete() && !viewModel.completed() ">Edit</button>
       </div>
        <div class="checkout-section-body">
            <div id="shipping_address_summary" >
                <!-- ko template: {
                    name: 'cart.shippingSummary',
                    data: shipments(),
                    if : (viewModel.shippingComplete() ||  viewModel.completed()) && shipments().length > 0 } -->
                <!-- /ko -->
                <!-- 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 class="alert alert-info" data-bind="visible: $data.detailLines().length == 0, html: 'Please add products to the ' + oConfig.labels.savedCarts + ' to continue'"></div>
        <div class="checkout-section-footer" data-bind="visible: !orderPlaced() && !viewModel.shippingComplete()">
            <button type="button" id="btn_continue_shipping" class="btn btn-primary pull-right" data-target="checkout_shipping" data-bind="click: allocateShipments, attr: { disabled: !viewModel.billingSectionValid() || $data.detailLines().length == 0 }">
                Continue Checkout
            </button>
        </div>
    </div>
</script>

<script type="text/html" id="cart.shippingActions">
    <ul class="nav nav-tabs">
        <!-- ko if: ofConfig.allowUserCreatedShipments && detailLines().length > 0-->
            <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>
        <!-- /ko -->
        <!-- ko if: ofConfig.bAllowShipToAdds && detailLines().length > 0 -->
            <li>
                <!-- ko template: 'cart.addAddressButton' --><!-- /ko -->
            <li>
        <!-- /ko -->
        <!-- ko if: viewModel.allowProductAdds() && ofConfig.showProductAddDropdown -->
            <!-- ko template: 'cart.addProductButton'--><!-- /ko -->
        <!-- /ko -->
    </ul>
</script>

<script type="text/html" id="cart.productQuickAdd">
    <div class="product-select">
        <div class="form-buttons input-append">
            <input type="text" id="sku_entry"
                data-bind="textInput: productFinderSearchTerm, 
                          autocompleteSku, 
                          executeOnEnter: handleSkuSubmission"
                name="sku"
                class="span8"
                placeholder="Add Product"
                autocomplete="off"
                autocapitalize="off"
                autocorrect="off">
            <button id="sku_submit"
                data-bind="click: handleSkuSubmission"
                class="btn"
                tabindex="-1"><i class="icon-plus"></i></button>
            <button id="find_product"
                data-bind="addModalHandler: { 'element' : $('button#find_product'), 'handler' : addFromProductFinder },
                           attr: { 'data-url': productFinderUrl }"
                class="btn global-modal"
                type="button"
                tabindex="-1"
                data-title="Find a Product"
                data-size="large"><i class="icon-search"></i></button>
        </div>
    </div>
    <div 
        class="well" style="max-width:450px;"
        data-bind="
            visible: viewModel.mainProduct() && !!!viewModel.mainProduct().configuratorEditData, 
            if: viewModel.mainProduct() && !!!viewModel.mainProduct().configuratorEditData
        " >
            <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">
        <div class="checkout-section-heading">
            <h3 class="checkout-section-heading__text">Finalize &amp; Place<span class="hidden-xs">&nbsp;Order</span> <i class="icon-ok-sign text-success" data-bind="visible: completed()"></i></h3>
        </div>
        <!-- ko template: { name: 'cart.errorList', data: _.filter(errorMessages(), function (error) { return error.errorType == 'ship_vias' || error.errorType == 'shipment'; } ) } --><!-- /ko -->
        <!-- ko if: viewModel.shippingComplete -->
            <div class="checkout-section-body">
                <div class="checkout-section-inner">
                    <div id="checkout_review" class="row-fluid">
                        <div class="span8">
                            <!-- 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() -->
                                <!-- 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 -->
                                <fieldset class="checkout-review__fieldset" id="payment_methods" data-bind="visible: !!$data.selectedOrderAction && $data.selectedOrderAction().showPaymentMethods()">
                                    <legend class="checkout-review__fieldset-content" data-bind="visible: !orderPlaced() && allItemsAllocated()">
                                        <i class="icon-lock icon-fixed-width"></i> Secure Payment Methods
                                    </legend>
                                    <!-- 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" id="controlgroup_quoteinfo" data-bind="if: (recordType() != 'cart' && ofConfig.showExpirationDate) && ((superUserOrderFormMode() && ofConfig.superUserAllowExpirationDateEdits) || viewModel.isValidDate(expirationDate()))">
                                    <legend class="checkout-review__fieldset-content">
                                        <i class="icon-pencil icon-fixed-width"></i> Quote Information
                                    </legend>
                                    <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" id="controlgroup_recurring" data-bind="if: !completed() && ((selectedOrderAction() && selectedOrderAction().showRecurringOrderSettings()) || viewModel.recordType() == 'recurring' ) ">
                                    <div class="checkout-review__fieldset-content">
                                        <!-- ko template: { name: 'cart.recurringDetails' } --><!-- /ko -->
                                    </div>
                                </fieldset>

                                <fieldset class="checkout-review__fieldset" data-bind="if: ofConfig.showOrderActionsInline">
                                    <legend class="checkout-review__fieldset-content" data-bind="if: viewModel.allowPlaceOrder() && shippingComplete() && paymentMethodID(), visible: orderActions().length > 1">
                                        <i class="icon-cog icon-fixed-width"></i> Choose an Order Action
                                    </legend>
                                    <!-- 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 -->
                                </fieldset>
                                <!--ko template: { name: 'cart.noteBookNotes', if : viewModel.noteBook().notes().length > 0  } --><!-- /ko -->
                            <!-- /ko -->
                        </div>
                        <!-- ko if: ofConfig.showPricingOrderEntry -->
                        <div class="span4">
                            <div class="sticky" data-bind="Stickyfill">
                                <!-- ko template: { name: 'cart.checkoutSummary' } --><!-- /ko -->
                            </div>
                        </div>
                        <!-- /ko -->
                    </div>
                </div>
            </div>
        <!-- /ko -->
    </div>
</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 btn-success" data-bind="click: function() { SetCouponCode(newCouponCode()); newCouponCode(''); }">Apply</button>
                </div>
                <!-- /ko -->
                <!-- ko if: couponCode -->
                <div class="alert alert-success">
                    <strong><span data-bind="text: couponCode"></span></strong> applied.&nbsp;<i style="cursor: pointer" class="icon-remove text-error" 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 btn-success" 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="well 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" 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" data-bind="if : $data.showComments">
                                <!-- ko template: 'cart.noteBookComments'--><!-- /ko -->
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
        <div class="form-actions" data-bind="foreach: orderActions">
            <!-- ko template: { name: 'cart.termsAndConditions' } --><!-- /ko -->
            <button
                class="btn btn-large  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: ($data.refID() == (viewModel.selectedOrderAction() && viewModel.selectedOrderActionRefId()) || $parent.orderActions().length == 1) && ($data.showButton())
            "></button>
        </div>
    </div>
</script>

<script type="text/html" id="cart.termsAndConditions">
    <label for="termsAgreement" class="checkbox" 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">
    <!-- ko template: { name: 'cart.couponEntry', if: ofConfig.showCoupon && !ofConfig.showCouponEntryInline } --><!-- /ko -->
    <!-- ko template: { name: 'cart.giftCertificateEntry', if: ofConfig.showGiftCertificate &&  !ofConfig.showGiftCertificateEntryInline } --><!-- /ko -->
    <div id="checkout_summary" class="panel panel-default" data-bind="with: viewModel">
        <div class="panel-heading">
            <b>Order Summary</b>
        </div>
        <table class="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: utils.formatMoney(productTotal())"></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: utils.formatMoney(productSubTotalBeforeDiscount())"></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: utils.formatMoney(productDiscountTotal())"></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: utils.formatMoney(productTotal())"></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.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 -->
                    </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: utils.formatMoney(taxTotal())"></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: utils.formatMoney(orderBalance())"></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">
            <label for="external_comments">
                Comments <small class="muted">(optional)</small>
            </label>
            <textarea
                id="external_comments"
                class="input-block-level"
                rows="3"
                autocomplete="off"
                data-bind="textInput: viewModel.customerComment">
            </textarea>
            <p data-bind="visible: viewModel.customerComment() != ''  "><a class="btn btn-small btn-block" data-bind="event : { 'click' : viewModel.saveCustomerComment }">Post Comments</a></p>
            <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>Comments for this order:</h3>
        <div class="convolog-entries">
            <ul class="list-group" data-bind="foreach: $data.noteBook().notes()">
                <li class="list-group-item">
                    <div>
                        <p data-bind="html: $data.externalNotes"></p>
                        <small class="muted"><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" data-bind="visible: !viewModel.errorMessages().length && viewModel.showConfirmationMessage() ">
        <div class="checkout-section-body">
            <div class="checkout-section-inner">
            <!-- ko if: viewModel.selectedLifecycleStage().confirmationMessage() != '' -->
                <div data-bind="attr: { 'class': 'confirmation-alert-box ' + selectedLifecycleStage().displayClass() }">
                    <i class="icon-3x pull-left"></i>
                    <h3 data-bind="html: selectedLifecycleStage().confirmationMessage()"></h3>
                </div>
            <!-- /ko -->
            <!-- ko if: viewModel.selectedLifecycleStage().confirmationMessage() == '' -->
                <div
                    class="alert"
                    data-bind="
                        css: {
                            'alert-error': viewModel.lifecycleStage() == 'cancelled',
                            'alert-success': 
                                function(){
                                    return (completed() || (viewModel.lifecycleStage() == 'pending' || viewModel.recordType() == 'recurring') ) || (!completed() && viewModel.lifecycleStage() !== 'cancelled')
                                }
                        },
                ">
                    <i class="icon-ok-sign icon-3x pull-left"></i>
                    <h3 class="text-success" data-bind="visible: completed() && viewModel.lifecycleStage() != 'cancelled'">Thank you for your order!</h3>
                    <h3 class="text-success" data-bind="visible: !completed() && viewModel.recordType() == 'recurring' ">Recurring Order Saved.</h3>
                    <h3 class="text-success" data-bind="visible: !completed() && viewModel.lifecycleStage() == 'pending' ">This order is pending approval.</h3>
                    <h3 class="text-success" data-bind="visible: !completed() && viewModel.lifecycleStage() != 'pending' && viewModel.lifecycleStage() != 'recurring' && viewModel.lifecycleStage() != 'cancelled' ">This order has been saved.</h3>
                    <h3 class="text-error" data-bind="visible: viewModel.lifecycleStage() == 'cancelled' ">This order was rejected.</h3>
                </div>
            <!-- /ko -->
                <!-- ko template: 'cart.printButton'--><!-- /ko -->
                <!-- 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="span6 well checkout-section__span">
                        <!-- ko template: 'cart.paymentMethodSummary' --><!-- /ko -->
                    </div>
                    <div class="span6 checkout-section__span" data-bind="css: { 'well': poNumber() || comments() }">
                        <div id="controlgroup_invoice_ponumber_summary" class="control-group checkout-section__summary-wrapper" data-bind="if: poNumber">
                            <div class="checkout-section__summary">
                                <label for="ponumber_summary" class="control-label">
                                    <strong data-bind="html: ofConfig.POLabel"></strong>
                                </label>
                                <div class="controls">
                                    <strong><span id="ponumber_summary" class="" data-bind="text: poNumber"></span></strong>
                                </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">
                <ul class="unstyled" data-bind="foreach: $data">
                    <li><strong><span data-bind="text: message"></span></strong></li>
                </ul>
            </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 items 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>Order Contact</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="span6 billing-address-summary__span">
                    <div class="well billing-address-summary__well">
                        <b>Order Contact</b>
                        <button
                            type="button"
                            id="contact-address"
                            class="btn btn-link btn-mini global-modal"
                            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="full"
                        >
                            Change
                        </button>
                        <!-- ko template: { name: 'cart.orderContactSummary', data: customer } --> <!-- /ko -->
                    </div>
                </div>
                <div class="span6 billing-address-summary__span">
                    <div class="well billing-address-summary__well">
                        <b>Billing Address</b>
                        <button
                            type="button"
                            id="billing-address"
                            class="btn btn-link btn-mini global-modal"
                             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="full"
                        >
                            Change
                        </button>
                        <!-- ko template: { name: 'cart.billingAddressSummary', data: billToAccount } --><!-- /ko -->
                    </div>
                </div>
            </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="input-mini text-right" data-bind="value: total().toFixed(2), event: { change: viewModel.superUserSetShipViaPrice }">
                        </div>
                    </div>
                <!-- /ko -->
                <!-- ko if: !ofConfig.showPricingOrderEntry -->
                <div class="sv-hidden-price pull-right" data-bind="html: utils.drawHidePriceMessage()"></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) }">
            <p>
                <i class="icon-info-sign"></i>
                <span data-bind="attr: { 'id' : 'sv-collect-info-msg' + parseInt($context.$index() + 1) }">This shipping method requires that you provide your own shipper account number to cover the shipping charges.</span>
            </p>
            <div class="input-append shipping-account-select" data-bind="attr: { 'id' : 'shipping-account-select' + parseInt($context.$index() + 1) }">

                <select class="input-xlarge selShipAcct" 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...',
                    validationOptions: { messageTemplate: null, insertMessages: true }
                "></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 -->
            </div>
            <!-- ko if : ofConfig.superUserAllowShipperAccountAdds -->
            <a class="btn btn-link 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 data-bind="if: !selectedShipVia.shippingAccountId.isValid() && selectedShipVia.shippingAccounts().length > 0">
                <p class="alert alert-error">Please select 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="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">
            <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(120, 'days').toDate(), //most quote systems only go out 120 days (after that, rates are not available)
                            constrainInput: true,
                            showOn:'both',
                            buttonText: '<i class=\'icon-calendar\'></i>',
                            beforeShowDay: function (date) {
                                return [isValidRequestedDate(date)];
                            }
                        }">
                <button type="button" class="btn" data-bind="attr: { disabled: viewModel.orderPlaced }, click: function(shipment) { $('#' + shipment.selectedShipVia.shipViaChoiceID()).datepicker('show') }, clickBubble: false">
                    <i class="icon-calendar"></i>
                </button>
            </div>
        </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-body" -->
        <div>
            <div class="checkout-section-inner">
                <div class="well">
                    <p data-bind="visible : viewModel.useMultiShipEditUI">Your order is being shipped to multiple locations.</p>
                    <!-- ko ifnot : viewModel.useMultiShipEditUI -->
                        <!-- ko template : { name: 'cart.addressSummaryInfo', data: $data[0].shipTo }--><!-- /ko-->
                    <!-- /ko -->
                </div>
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.addressSummaryInfo">
    <p data-bind=" forEach: $data " class="address-summary">
        <!-- ko if: attention -->
            <span data-bind="text: attention() + ', '"></span>
        <!-- /ko -->
        <!-- ko if: company -->
            <span data-bind="text: company() + ', '"></span>
        <!-- /ko -->
        <!-- ko if: firstName() || lastName() -->
            <span data-bind="text: firstName() + ' ' + lastName() + ', '"></span>
        <!-- /ko -->
        <span data-bind="text: address1() + ',', visible: address1"></span>
        <span data-bind="text: address2() + ',', visible: address2"></span>
        <span data-bind="text: address3() + ',', visible: address3"></span>
        <span data-bind="text: address4() + ',', visible: address4"></span>
        <span data-bind="text: address5() + ',', visible: address5"></span>
        <span 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>
        </span>
        <span data-bind="text: country; visible: country"></span>
    </p>
</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: utils.formatMoney(orderDetail.instanceUnitPrice())"></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 -->
                        on shipment
                    </div>
                </div>
            </div>
        </div>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.shipmentItemTable">
    <!-- ko if: details().length > 0 -->
        <!-- ko template: { afterRender: function() { $(document).trigger('enhance.tablesaw'); } } -->
            <table class="tablesaw cart-table" data-tablesaw-mode="stack">
                <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' -->
                    <th></th>
                    <!-- /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.configOptions", data: orderDetail } --><!-- /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: utils.formatMoney(orderDetail.instanceUnitPrice())"></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>
                        <!-- 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 -->
</script>

<script type="text/html" id="cart.additionalDetailLineInfo">
</script>

<script type="text/html" id="cart.configOptions">
    <!-- ko if : configuratorJson.choices -->
        <div class="config-options" style="margin:0;padding-bottom:0;border: 1px solid #ddd;">
            <div class="config-options__title" style="background-color: #ddd; padding:5px 10px; margin: 0 0 5px 0;float:none;">
                <span class="config-options__type" style="font-weight: bold;" data-bind="text: configuratorJson.configType() === 'cartoptions' ? 'Options' : 'Configuration Options'"></span>
                <span class="pull-right config-options__details" data-bind="visible: configuratorJson.configType() !== 'cartoptions'">
                    <!-- ko template: { name: 'cart.productEditLink', data: { title: 'Edit Configuration', linkText: 'Edit', detailLine: $data } } --><!-- /ko -->
                </span> 
            </div>
            <ul class="configOptions 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">
                <thead class="config-options__thead">
                    <th class="config-options__qty-title">Qty</th>
                    <th class="config-options__price-title">Item 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>
    <!-- /ko -->
</script>

<script type="text/html" id="cart.addAddressButton">
    <a
        type="button"
        class="global-modal"
        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-sign icon-fixed-width"></i>Add
            <span class="hidden-xs hidden-sm">a new</span>
            <span class="hidden-xs">address</span>
    </a>
</script>

<script type="text/html" id="cart.addProductButton">
    <li class="dropdown pull-right hide">
        <a
            type="button"
            class="add-product  dropdown-toggle"
            data-toggle="dropdown">
                <i class="icon-plus-sign icon-fixed-width"></i>Add Products <span class="caret"></span></a>
        </a>
        <ul class="dropdown-menu">
            <li>
                <a
                    class="global-modal add-bulk"
                    data-size="full"
                    data-title="Add Products"
                    data-bind="
                        attr: { 'href' : 'bulk_atc.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey() },
                        addModalHandler: { 'element' : $('.add-bulk'), 'handler' : viewModel.genericModalComplete },
                        click: function() { utils.setActiveQuote(viewModel.orderKey()); return true; }"
                >Quick Add</a>
            </li>
            <li>
                <a
                    class="global-modal add-browse"
                    data-size="full"
                    data-title="Add Products"
                    data-bind="
                        attr: { 'href' : 'pc_combined_results.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey() },
                        addModalHandler: { 'element' : $('.add-browse'), 'handler' : viewModel.genericModalComplete },
                        click: function() { utils.setActiveQuote(viewModel.orderKey()); return true; }"
                >Browse</a>
            </li>
            <li>
                <a
                    class="global-modal add-from-fave"
                    data-size="full"
                    data-title="Add Products"
                    data-bind="
                        attr: { 'href' : 'favorite_lists_man.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey() },
                        addModalHandler: { 'element' : $('.add-from-fave'), 'handler' : viewModel.genericModalComplete },
                        click: function() { utils.setActiveQuote(viewModel.orderKey()); return true; }"
                >From Favorites</a></li>
            <li><a
                    class="global-modal add-from-so"
                    data-size="full"
                    data-title="Add Products"
                    data-bind = "
                        attr: { 'href' : 'erp_manage_sales_orders.asp?modalaction=addProduct&modal=1&o_key=' + viewModel.orderKey()},
                        addModalHandler: { 'element' : $('.add-from-so'), 'handler' : viewModel.genericModalComplete },
                        click: function() { utils.setActiveQuote(viewModel.orderKey()); return true; }"
                >From Sales Order</a></li>
        </ul>
    </li>
</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">
    <img
        data-bind="attr : { alt: sku() + ' - ' + name(),
                src: utils.buildImagePath(commodity.pic.thumb()) },
                visible: !oConfig.fastTrack && (!parentProductID().trim() || !hasParentInCart() )"
        class="media-object pull-left cart-item-pic"
        onerror="utils.handleImageError(this)">
    <div class="pull-left cart-item-pic" data-bind="visible: !oConfig.fastTrack && parentProductID().trim() && hasParentInCart()">&nbsp;</div>
    <div class="media-body">
        <div class="media-heading">
            <b data-bind="html: name"></b>
            <!-- ko if : promoID -->
                <span class="promo-icon" data-bind="attr: { 'title' : promoDescription() } ">P</span>
            <!-- /ko -->
            <p class="text-xsmall muted" data-bind="text: sku, visible: !parentProductID().trim() || !hasParentInCart()"></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 data-bind="if: ofConfig.AllowWarehouse && $data.productWarehouse">
                <span data-bind="html: ofConfig.warehouseLabel + ' ' + $data.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>
            </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 -->
        </div>

        
        <!-- ko if:$data.editing() && viewModel.mainProduct() -->
            <div style="max-width: 300px;">
                <!-- ko template: { name: 'catalog.detail_info', data:viewModel.mainProduct } --><!-- /ko -->
                <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 } --><!-- /ko -->
            </div>
        <!-- /ko -->


        <!-- ko if : viewModel.superUserOrderFormMode() && ofConfig.superUserAllowProductPriceEdits && $data.qtyDisplayType() == 'input' && !$data.editing() && ofConfig.showPricingOrderEntry -->
            <div class="cart-item-price">
                <p class="input-prepend input-append">
                    <span class="add-on">$</span>
                    <input type="number" class="input-small" step=".01" data-bind="
                        value: price,
                        attr: {
                            'id' : 'price-' + orderDetailKey()
                        },
                        event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <!-- ko if: priceCalculationType() == 'fixed' -->
                        <a href="#0" class="add-on" data-bind="event: { click: viewModel.resetSuperUserPriceOverride }, html: ofConfig.superUserResetPriceHelpText">
                        </a>
                    <!-- /ko -->
                </p>
                <span class="help-block" data-bind="if: viewModel.superUserRestrictMinPrice() & superUserMinPrice() != null">Min: <span data-bind="html: utils.formatMoney(superUserMinPrice())"></span></span>
                <!-- ko if: ofConfig.showSUPriceControls && (commodity.cost() || commodity.retailPrice()) -->
                    <!-- ko template: 'cart.priceHelper' --><!-- /ko -->
                <!-- /ko -->
            </div>
        <!-- /ko -->
        <!-- ko if : (!(viewModel.superUserOrderFormMode() && ofConfig.superUserAllowProductPriceEdits) || $data.qtyDisplayType() == 'text') && !$data.editing() && ofConfig.showPricingOrderEntry -->
            <div class="cart-item-price" data-bind="html: utils.formatMoney(instanceUnitPrice())"></div>
        <!-- /ko -->

        <!-- ko if : !ofConfig.showPricingOrderEntry  -->
            <div class="cart-item-hiddenprice" data-bind="html: utils.drawHidePriceMessage()"></div>
        <!-- /ko -->

        <!-- ko if :  viewModel.useMultiShipEditUI() || $data.qtyDisplayType() =='text' || !viewModel.allowProductAdds() && !$data.editing() -->
            <div class="cart-item-qty">
                <label>
                    <input type="text" class="qty-input" disabled data-bind="attr: { value: viewModel.getTotalQty(instance()) }">
                    &nbsp;
                    <!-- ko if:ofConfig.showUom -->
                    <span class="uom" data-bind="text: $data.uom"></span>
                    <!-- /ko -->
                    on <span class="order" data-bind="visible:!viewModel.useMultiShipEditUI()">order</span><span class="shipment" data-bind="visible: viewModel.useMultiShipEditUI()">shipment</span>
                </label>
                <!-- ko if : viewModel.allowQtyControls() -->
                    <!-- ko template: 'cart.qtyControlSettings' --><!-- /ko -->
                <!-- /ko -->
            </div>
        <!-- /ko -->


        <!-- ko if : !viewModel.useMultiShipEditUI() && $data.qtyDisplayType() =='input' &&  viewModel.allowProductAdds() && !$data.editing()-->
            <div class="cart-item-qty">
                <label>
                    <input type="number" class="qty-input"
                        data-bind="
                            value: qty,
                            attr: {
                                'id' : 'qty-ship-' + orderDetailKey(),
                                'min' : minQty(),
                                'step' : qtyIncrement() || 1,
                                'max' : maxQty() || undefined
                            },
                            validateQty
                        ">
                    <span
                        data-bind="
                            attr:
                            {
                                'data-key' : orderDetailKey()
                            },
                            visible:  minQty() > 1 || maxQty() > 1 || qtyIncrement() > 1">
                        <a href="#0"
                            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="icon-question-sign"></i>
                        </a>
                    </span>
                    &nbsp;
                    <!-- ko if:ofConfig.showUom -->
                    <span class="uom" data-bind="text: $data.uom"></span>
                    <!-- /ko -->
                    on order
                </label>
                <!-- ko if : viewModel.allowQtyControls() -->
                    <!-- ko template: 'cart.qtyControlSettings' --><!-- /ko -->
                <!-- /ko -->
            </div>
        <!-- /ko -->
        <!-- <div class="text-small muted" data-bind="attr: { 'data-key' : orderDetailKey() } ">
            <div id="qty_controls_msg" >
                <span data-bind="if: minQty() > 0">
                    <span data-bind="text: oConfig.labels.minQty"></span>: <span data-bind="text: minQty()"></span><br>
                </span>

                <span data-bind="if: maxQty() > 0">
                    <span data-bind="text: oConfig.labels.maxQty"></span>: <span data-bind="text: maxQty()"></span><br>
                </span>

                <span data-bind="if: qtyIncrement() && qtyIncrement() !== 1">
                    <span data-bind="text: oConfig.labels.step"></span>: <span data-bind="text: qtyIncrement()"></span><br>
                </span>
            </div>
        </div> -->
        <div class="product-delete-edit-wrap">
            <!-- ko if: viewModel.showRemoveLink($data) -->
                <span class="product-delete">
                    <a href="" data-bind="event: { click: viewModel.removeProduct }, visible: !editing()" title="Remove this item from your Order?" class="text-xsmall">
                        <i class="icon icon-small icon-remove"></i> <span class="visible-lg">remove</span>
                    </a>
                </span>
                <br />
            <!-- /ko -->
            <!-- ko if: viewModel.allowProductAdds() && ofConfig.allowProductEditInEditView -->
                <!-- ko template: { name: 'cart.productInlineEditLinks' } --><!-- /ko -->
            <!-- /ko -->
        </div>
    
        <!-- ko if: viewModel.recordType() === 'recurring' && !editing()-->
            <div class="order-items-recurring">
                <div class="order-items-label visible-xs visible-sm">Schedule</div>
                <!-- ko template: { name: 'cart.recurringLineDetails' } --><!-- /ko -->
            </div>
        <!-- /ko -->
    </div>
</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 line item" class="text-xsmall">
            <i class="icon icon-small icon-edit"></i> <span class="visible-lg">edit</span>
        </a>
        <a href="" style="display: block; wrap: none;" data-bind="event: { click: viewModel.cancelEditProduct }, visible: editing" title="Cancel edits" class="text-xsmall">
            <i class="icon icon-small icon-remove"></i> <span class="visible-lg">cancel</span>
        </a>
    </span>
</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 },
                            text: 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" data-bind="if: shipments().length > 0 ">
                <div class="address-select">
                    <label>Ship to this address:</label>
                    <div class="input-append" data-bind="with: shipments()[0]">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                    </div>
                </div>
            </div>
            <p>&nbsp;</p>
            <!-- ko template: { name: 'cart.productQuickAdd', if: viewModel.allowProductAdds() && ofConfig.showProductQuickAddInEditView } --><!-- /ko -->
            <p>&nbsp;</p>
            <div class="items-on-order">
                <label>Items on Order:</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 -->
    <!-- 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="input-append" data-bind="with: shipments()[0]">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                    </div>
                </div>
            </div>
            <div class="items-on-order span6">
                <label>Items on Order:</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.shipToSelect">
    <select class="input-auto" data-bind="
        options: availableAddresses,
        optionsText: function(item){
            return item.name();
        },
        value: shipTo
    ">
    </select>
</script>

<script type="text/html" id="cart.shipToSelectOptGroups">
    <select class="input-auto"
            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>
    <span class="add-on" data-bind="visible: $data.shipTo().global() == 0 && viewModel.allowShaEdits()">
        <a class="edit-shipto global-modal"
           data-size="full" data-bind="
                addModalHandler: { 'element' : $('#shipping_address_summary .global-modal'), 'handler' : function(data){ apiGetShippingAddresses(data); } },
                attr: {
                    'href': 'account.asp?modalaction=editshipto&modal=1&o_key=' + viewModel.orderKey() + '&sha_id=' + $data.shipTo().key()
                },
                visible: viewModel.allowShaEdits()
            ">Edit</a>
    </span>
</script>

<script type="text/html" id="cart.assignItemsToShipTos">
    <div data-bind="foreach: $data">
        <!-- ko if: parentProductID().trim() == '' || !hasParentInCart() -->
        <div class="row-fluid checkout-multiship-row">
            <div class="span5">
                <div class="media" data-bind="template: { name: 'cart.itemCard' }"></div>
            </div>
            <div class="span7">
                <!-- div data-bind="foreach: viewModel.itemShipToMap().filter(function(shipToMap){ return shipToMap.instance() == instance() }) " -->
                <div 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(),
                                    'step' : $parent.qtyIncrement() || 1,
                                    'max' : $parent.maxQty() || undefined
                                },
                                disable: $parent.qtyDisplayType() == 'text',
                                validateQty
                            ">
                        <!-- ko template: 'cart.shipToSelectOptGroups'--><!-- /ko -->
                        <!-- ko if: $index() != 0 -->
                            <span class="add-on">
                                <a class="remove-shipto" href="#" data-bind="click: removeItemToShipToMap, attr: { 'data-index' : $index}">Remove</a>
                            </span>
                        <!-- /ko -->
                    </div>
                    <p>
                        <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>
                    </p>
                </div>
            </div>
        </div>
        <!-- /ko -->
    </div>
</script>

<script type="text/html" id="cart.itemShipToMapPreview">
     <table class="tablesaw" data-tablesaw-mode="stack">
        <thead>
            <th>#</th>
            <th>Ship to address</th>
            <th>Items 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">
        <!-- ko if: viewModel.useMultiShipEditUI() && !viewModel.allItemsAllocated() -->
            <thead>
                <th></th>
                <th>
                    Description
                </th>
                <th>
                    Qty
                </th>
                <th>
                    Item Price
                </th>
                <th>
                    Total
                </th>
            </thead>
        <!-- /ko -->
        <!-- ko if: viewModel.allItemsAllocated() || !viewModel.useMultiShipEditUI() -->
            <thead>
                <th>
                    Description
                </th>
                <th>
                    Qty
                </th>
                <th>
                    Item 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">
    <a data-bind="visible: ofConfig.collapsePriceControls" href="#0" onclick="$(this).next('.collapse').toggleClass('in'); return false;">
        Pricing Controls <i class="icon-angle-down"></i>
    </a>
    <span data-bind="css: { 'collapse': ofConfig.collapsePriceControls }" style="margin-top: 5px;display:block;">
        <!-- ko if: commodity.cost() -->
            <label>
                <div class="input-append">
                    <input type="number" class="qty-input" step="1" data-bind="
                        value: markupPercent,
                        attr: {
                            'id' : 'markupPercent-' + orderDetailKey(),
                            'min': minMarkupPercent
                        },
                        event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">%</span>
                </div>&nbsp;
                Markup
            </label>
        <!-- /ko -->
        <!-- ko if: commodity.retailPrice() -->
            <label>
                <div class="input-append">
                    <input type="number" class="qty-input" step="1" data-bind="
                    value: discountPercent,
                    attr: {
                        'id' : 'discountPercent-' + orderDetailKey(),
                        'max': maxDiscountPercent
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">%</span>
                </div>&nbsp;
                Discount
            </label>
        <!-- /ko -->
        <!-- ko if: commodity.cost() -->
            <label>
                <div class="input-append">
                    <input type="number" class="qty-input" step="1" data-bind="
                    value: grossMarginPercent,
                    attr: {
                        'id' : 'grossMarginPercent-' + orderDetailKey(),
                        'min': minGrossMarginPercent
                    },
                    event: { change: viewModel.setItemShipToMapPrice($data) }
                    ">
                    <span class="add-on">%</span>
                </div>&nbsp;
                Gross margin
            </label>
        <!-- /ko -->
        <!-- ko if: commodity.cost() -->
            <label>
                <div class="input-prepend">
                    <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) }
                    ">
                </div>&nbsp;
                Gross margin
            </label>
        <!-- /ko -->
    </span>
</script>

<script type="text/html" id="cart.qtyControlSettings">
    <a data-bind="visible: ofConfig.collapseQtyControls" href="#0" onclick="$(this).next('.collapse').toggleClass('in'); return false;">
        Qty Controls <i class="icon-angle-down"></i>
    </a>
    <p data-bind="css: { 'collapse': ofConfig.collapseQtyControls, 'well': !ofConfig.collapseQtyControls }" style="margin-top: 5px;">
        <!-- ko if: $data.qtyDisplayType() =='input' -->
            <label>
                <input type="number" min="1" class="qty-input"
                    data-bind="
                        value: suMinQty,
                        attr: {
                            'id' : 'minQty' + orderDetailKey()
                        }
                    ">
                &nbsp;
                Min Qty
            </label>
            <label>
                <input type="number" min="0" class="qty-input"
                    data-bind="
                        value: suMaxQty,
                        attr: {
                            'id' : 'maxQty' + orderDetailKey()
                        }
                    ">
                &nbsp;
                Max Qty
            </label>
            <label>
                <input type="number" min="1" class="qty-input"
                    data-bind="
                        value: suQtyIncrement,
                        attr: {
                            'id' : 'qtyIncrement' + orderDetailKey()
                        }
                    ">
                &nbsp;
                Qty Increment
            </label>
        <!-- /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>
    </p>
</script>

<script type="text/html" id="cart.paymentMethodList_radio">
    <div class="paymentmethods --radio control-group">
        <div class="control-label"><strong>Select Payment Method</strong></div>
        <div class="controls" data-bind="foreach: payMethods">
            <label class="paymentmethod">
                <input type="radio" name="shipmethod" data-bind="value: $data.paymentMethodKey(), checked: $parent.paymentMethod.paymentMethodKey(), click: $parent.setPaymentMethod">
                <span data-bind="text: name"></span>
            </label>
        </div>
    </div>
</script>

<script type="text/html" id="cart.paymentMethodList_tabs">
    <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': description,
                                                    href: '#method_' + paymentType()
                                            },
                                            text: name,
                                            click: $parent.setPaymentMethod,
                                            clickBubble: true"
                            data-toggle="pill"
                            rel="popover"
                            data-trigger="hover"
                            data-placement="top"></a>
            </li>
    </ul>
</script>

<script type="text/html" id="cart.paymentMethods">
    <!-- ko template: { name: 'cart.paymentMethodList_' + ofConfig.payMethodDisplayType } --><!-- /ko -->

    <div class="tab-content">
        <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="css: { active: paymentMethodID() && paymentMethod.paymentType() == 'billme' }">
        </div>
        <div id="method_ach-check" class="tab-pane" data-bind="css: { active: 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="css: { active: paymentMethodID() && paymentMethod.paymentType() == 'paypal' }">
        </div>
    <div id="controlgroup_invoice_ponumber" class="control-group" data-bind="if: paymentMethodID && paymentMethod.collectPO()">
            <hr>
        <label for="ponumber" class="control-label" data-bind="html: ofConfig.POLabel"></label>
        <div class="controls">
            <input type="text" 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="if: viewModel.paymentMethod.poRequired()"/>
                <p id="ponum_help" class="help-block text-small" data-bind="if: viewModel.paymentMethod.poRequired()">(required)</p>
        </div>
    </div>
    <div id="controlgroup_invoice_comments" class="control-group" data-bind="if: ofConfig.showFulfillmentcomments">
            <hr>
        <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, attr: { maxlength: ofConfig.fulfillmentcommentsMaxLength }"></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 Items 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">
            <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.bUseExpectedShipDate">
                        <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" data-bind="attr: { id: key }">
            <div class="list-group shipment-list__group">
                <div class="list-group-item clearfix shipment-list__item">
                    <div data-bind="if : $parent.shipments().length > 1" class="shipment-title pull-left">
                        <!-- ko template: { name: 'cart.addressSummaryInfo', data: shipTo, if: !showShippingAddressEdit() && shipToValid() } --><!-- /ko -->
                        <!-- ko template: { name: 'cart.shipmentSplitByDisplay' } --><!-- /ko -->
                    </div>
                    <div class="pull-right shipment-list__text">
                        <a class="shipment-list__link" href="#0" data-bind="click:
                        function() {
                            viewModel.shippingComplete(false)
                        }, html: ofConfig.sEditShipmentText"></a>
                        <i
                            class="icon-large icon-question-sign shipment-help shipment-list__link-icon"
                            data-trigger="hover"
                            data-placement="left"
                            data-bind="popover, 
                                attr: {
                                    'data-content':
                                        function(){
                                            if(utils.getCookie('activequote') && utils.getCookie('activequote').length == 32){
                                                return ofConfig.shipmentListEditBtnHelpTextQuote;
                                            }else{
                                                return ofConfig.shipmentListEditBtnHelpText;
                                            }
                                        }(),
                                    'title': ofConfig.shipmentListEditBtnHelpTitleText
                                }">
                        </i>
                    </div>
                </div>
                <!-- ko if : ofConfig.useProductSummaryTableView -->
                    <div class="list-group-item">
                        <div class="row-fluid">
                            <!-- ko template: { name: 'cart.shipmentItemTable' } --><!-- /ko -->
                        </div>
                    </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="well" >
                                    <label data-bind="html: ofConfig.shipmentListChooseMethodLabel"></label>
                                    <!-- ko template: { name: 'cart.shipmentMethodSelector' } --><!-- /ko -->
                                </div>
                                <!-- ko template: { if : ofConfig.CollectShipAccount, name: 'cart.shipperAccountSelector' }--><!-- /ko -->
                            </div>
                            <div class="span5" data-bind="if: ofConfig.bShowShipmentComment || ofConfig.UseRequestedDay || ofConfig.bUseExpectedShipDate">
                                <h5 data-bind=" html : ofConfig.sShipmentCommentTitle"></h5>
                                <!-- 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">
                                <label data-bind="html: ofConfig.shipmentListChooseMethodLabel"></label>
                                <!-- 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="help-inline" data-bind="visible: field.isModified() && !field.isValid(), text: field.error"></p>
</script>

<script type="text/html" id="cart.processingOverlay">
    <div id="appLoadingWidget" class="app-loading">
        <svg id="appLoadingSpinner" class="app-loading-spinner" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="170px" height="170px" viewBox="-220 312 170 170" enable-background="new -220 312 170 170" xml:space="preserve">
            <g class="app-loading-spinner-svg">
                <path fill="#AAAAAA" d="M-67.6,398.2l13.5-4c-0.3-5.9-1.1-11.6-2.4-17l-14-0.3c-0.5-1.6-1.1-3-1.6-4.6l10.8-8.9 c-2.4-5.1-5.4-10.2-8.6-14.8l-13.2,5.1c-1.1-1.3-2.2-2.4-3.2-3.5l6.5-12.4c-4.3-3.8-8.9-7.3-13.8-10.2l-10,9.7 c-1.3-0.8-3-1.3-4.3-2.2l1.3-14c-5.4-1.9-10.8-3.5-16.7-4.3l-5.7,12.9c-1.6-0.3-3.2-0.3-4.9-0.3l-4-13.5c-5.9,0.3-11.6,1.1-17,2.4 l-0.3,14c-1.6,0.5-3,1.1-4.6,1.6l-8.9-10.8c-5.1,2.4-10.2,5.4-14.8,8.6l5.1,13.2c-1.3,1.1-2.4,2.2-3.5,3.2l-12.4-6.5  c-3.8,4.3-7.3,8.9-10.2,13.8l9.7,10c-0.8,1.3-1.3,3-2.2,4.3l-14-1.3c-1.9,5.4-3.5,10.8-4.3,16.7l12.9,5.7c-0.3,1.6-0.3,3.2-0.3,4.9 l-13.5,4c0.3,5.9,1.1,11.6,2.4,17l14,0.3c0.5,1.6,1.1,3,1.6,4.6l-10.8,8.9c2.4,5.1,5.4,10.2,8.6,14.8l13.2-5.1 c1.1,1.3,2.2,2.4,3.2,3.5l-6.5,12.4c4.3,3.8,8.9,7.3,13.8,10.2l10-9.7c1.3,0.8,3,1.3,4.3,2.2l-1.3,14c5.4,1.9,10.8,3.5,16.7,4.3 l5.7-12.9c1.6,0.3,3.2,0.3,4.9,0.3l4,13.5c5.9-0.3,11.6-1.1,17-2.4l0.3-14c1.6-0.5,3-1.1,4.6-1.6l8.9,10.8 c5.1-2.4,10.2-5.4,14.8-8.6l-5.1-13.5c1.3-1.1,2.4-2.2,3.5-3.2l12.4,6.5c3.8-4.3,7.3-8.9,10.2-13.8l-9.7-10c0.8-1.3,1.3-3,2.2-4.3  l14,1.3c1.9-5.4,3.5-10.8,4.3-16.7l-12.9-5.7C-67.9,401.4-67.6,399.8-67.6,398.2z M-135,437.3c-22.4,0-40.4-18.1-40.4-40.4 c0-22.4,18.1-40.4,40.4-40.4s40.4,18.1,40.4,40.4C-94.6,419.2-112.7,437.3-135,437.3z"></path>
            </g>
            <image class="app-loading-spinner-img" src="templates/gfx/loading/loading.gif" alt="Loading..."></image>
        </svg>
  </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 -->
        <div class="text-small text-warning"><i class="icon-warning-sign icon-large"></i> <b><span data-bind="text:qty() - Math.max(0, commodity.qtyAvailable() - commodity.qtyBuffer())"></span></b> on back order. <b><span data-bind="text: Math.max(0, commodity.qtyAvailable() - commodity.qtyBuffer())"></span></b> will ship.</div>
    <!-- /ko -->
</script>



<script type="text/html" id="cart.recurringDetails">
    <legend >           
        <i class="icon icon-repeat icon-fixed-width"></i> Schedule Details
    </legend>       
    <!-- 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 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> 
    <hr>
</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">

		var quickAccessLinkViewModel = {
			quickAccessLinks: ko.observableArray()
		};

		var qaConfig = {
			menuTitle: "Quick Access",
			showLinks: false,
			useFilter: false			
		}

		if(qaConfig.showLinks || qaConfig.useFilter){
			var sApiBaseUrl = Config.apiBaseUrl;
			var sessionKey = "23CC993A1E514976B551384C0DC27E3F";

			function addEventHandlersToLinks(){
				if(qaConfig.showLinks){
					$('.filter-menu ul a[href!="#"]:not(.add a), #quick_access_links a.qa-example')
						.prepend(
							'<span class="add-to-quick-access" title="Add to ' + qaConfig.menuTitle + '" onclick="addToQuickAccess(this); return false;">' +
								'<i class="icon-star"></i>' +
							'</span>'
						);
				}

				if(qaConfig.useFilter){
					$("#link-filter, .filter-form").on('keyup reset', function(){
						linkSearch();
					});
				}

			}

			var linkSearch = _.debounce(debouncedSearch, 300);

			function debouncedSearch(){
				var filter = $("#link-filter").val();

				$('.filter-menu').css('opacity', '0');

				//Clear all previous filters (this solves backspacing and typing a new phrase without removing the filter entirely)
				$(".filter-menu li").hide().removeClass('ignore');
				$(".filter-menu a").removeClass('highlight');
				//open all parents so all links can be seen.
				$('.filter-menu li.link-parent.drop').addClass('open');
				
				//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) {
						$(this).parent().hide();
						$(this).removeClass('highlight');
					}else{
						$(this).parent().show();
						$(this).addClass('highlight');
						$(this).parent().addClass('ignore');

						//If this is a parent top level, enable all links below but collapse the menu
						if($(this).parent().hasClass('link-parent')){
							$(this).parent().removeClass('open');
							$(this).parent().find('li').addClass('ignore').removeClass('open').show();
						}
					}
				});

				//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(){
					if ($(this).text().search(new RegExp(filter, "i")) < 0) {
						//Doesn't match.  Hide this link's LI and any child LIs
						if($(this).parent().hasClass('ignore')){
							$(this).parent().show();
						}else{
							$(this).removeClass('highlight');
							$(this).parent().hide();
						}
					}else{
						//Match. Show this link's LI and any parent/child li.link-parent
						$(this).addClass('highlight')
								$(this).parent().show();
								if(~$(this).parent().prop('className').indexOf('manage')){
									//Display the "add" link for any "manage" link that matchs
									if ($(this).parent('li').next('li').prop('className')) {
										if(~$(this).parent('li').next('li').prop('className').indexOf('add')){
											$(this).parent('li').next('li').show().addClass('ignore');
										}
									}
								}
								//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').addClass('ignore').show();
								$(this).parent().find('li.link-parent').removeClass('open');
					}
				});
				
				if( filter == ''){
					$('.filter-menu li.link-parent.drop').removeClass('open').removeClass('ignore').removeClass('highlight');
					$(".filter-menu li").show().removeClass('ignore');
					$('.filter-menu a').removeClass('highlight');
				}
			$('.filter-menu').css('opacity', '1');
			}
			
			function addToQuickAccess(link){
				var link  = $($(link).parent());
				var href  = link[0].href;
				var name  = link[0].innerText.trim();
				var key   = link.parent().attr('data-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){
						if(~link.parent().prop('className').indexOf('manage') && (~link.parent().next() && ~link.parent().next().prop('className').indexOf('add'))){
							var childhref = link.parent().next().children()[0].href;
							var childname = link.parent().next().children()[0].innerText.trim();
							var childKey  = link.parent().next().attr('data-key')

							quickAccessLinkViewModel.quickAccessLinks.push({
								href: href,
								name: name,
								key: key,
								addLink: {
									href: childhref,
									name: childname,
									key: childKey
								}
							});
						}else{
							quickAccessLinkViewModel.quickAccessLinks.push({
								href: href,
								name: name,
								key: key
							});
						}
						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 getQuickLinks() {
				$.ajax({
					url: sApiBaseUrl + 'QuickAccessLinks',
					headers: { 
						'Authorization' : 'Bearer ' + sessionKey, 
						'Accept': 'application/json' 
					},
					success: function(data) {
						quickAccessLinkViewModel.quickAccessLinks(data);
					},
					error: function(error){
						console.log(error);
					}
				});
			}


			$( function(){ 
				addEventHandlersToLinks();
				getQuickLinks();
			});
		}
	</script>



	<script type="text/html" id="links.quickAccessLinks">

		<div id="quick_access_links" class="linkset vertical accordion">
			<div class="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 style="display: block">
					<li><a href="https://sbshutter.cimproduction.com" class="qa-example">Home Page</a></li>
				</ul>
			</div>
			<div data-bind="visible: quickAccessLinks().length > 0 ">
				<div
					data-bind="sortable: 
					{
						data: quickAccessLinks,
						afterMove: saveQuickLinks,
						containment: 'parent'
					}">
					<ul data-bind="css: { hybrid: $data.addLink }">
						<li data-bind="css: { manage: $data.addLink }">
							<a class="quick-access" data-bind="attr: { href : $data.href } ">
								<span data-bind="html: $data.name "></span>
								<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>
							</a> 
						</li>
						<li class="add" data-bind="visible: $data.addLink">
							<!-- ko if: $data.addLink -->
								<a data-bind="
									attr: { 
										href: $data.addLink.href, 
										title: 'Add ' + $data.addLink.name 
									}, 
									html: $data.addLink.name">
								</a>
							<!-- /ko -->
						</li>
					</ul>
				</div>
			</div>
		</div>
	</script>

<!-- Customized to check contextTabs.show to determine if each context tab should show. This is set in JS hook cimDashboardAfterEntityConfigViewModel -->
<script type="text/html" id="cim.portal.header_custom">
	
</script>

<script type="text/html" id="catalog.uom_input_custom">
	<!-- 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> 
		
		<br>
		<span data-bind="if: opt12() == 'Y' && opt10()">
			<span data-bind="html: '$'+(uomPrice()[0].price()/opt10()).toFixed(3)"></span> / <span data-bind="text: opt11"></span></small>
		</span>
	<!-- /ko -->

</script>

<script type="text/html" id="cart.shipmentItemTable_custom">
	<!-- ko if: details().length > 0 -->
		<!-- ko template: { afterRender: function() { $(document).trigger('enhance.tablesaw'); } } -->
			<table class="tablesaw cart-table" data-tablesaw-mode="stack">
				<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>
					<th class="cart-price__th" data-bind="text: ofConfig.labels.cartItemPrice"></th>
					<th class="cart-total__th" data-bind="text: ofConfig.labels.cartTotal"></th>
					<!-- ko if: ofConfig.allowProductEditInFinalStep && viewModel.recordType() != 'recurring' -->
					<th></th>
					<!-- /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 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>
										<span data-bind="if: viewModel.allowWarehouseSelection() && !viewModel.useMultiShipEditUI()">
											<!-- ko template: { name: 'cart.productEditLink', data: { title: 'Change Warehouse', linkText: 'Change Warehouse', detailLine: orderDetail } } --><!-- /ko -->
										</span>
									</p>
									<!-- ko if : ofConfig.bShowCartOptions && orderDetail.cartOption -->
										<p data-bind="text: orderDetail.cartOption"></p>
									<!-- /ko -->
									<!-- ko template: { name: "cart.configOptions", data: orderDetail } --><!-- /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>
						<td class="instance-unit-price__td">
							<span data-bind="html: utils.formatMoney(orderDetail.instanceUnitPrice())"></span>
						</td>
						<td class="instance-ext-price__td">
							<span data-bind="html: utils.formatMoney(orderDetail.instanceExtPrice())"></span>
						</td>
							<!-- ko if: ofConfig.allowProductEditInFinalStep && viewModel.recordType() != 'recurring' -->
							<td class="recurring__td">
								<!-- ko template: { name: 'cart.productInlineEditLinks', data: orderDetail } --><!-- /ko -->
							</td>
							<!-- /ko -->
						</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 -->
</script>



<script>
	registerHook({
		name: 'productModelBottom',
		func: function(args) {
			var self = args.self;

			// Have to override this in order to call the custom template...
			self.uomTemplate = ko.computed(function() {
				if (self.selectedProduct().uomPrice().length > 1) {
					return 'catalog.uom_select';
				} else {
					return 'catalog.uom_input_custom';
				}
			});

			self.mapPriceMessage = function () {
				if (self.mapPriceType() === 'show_message' || oConfig.isLoggedIn) {
					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 '';
				}
			}();
		}
	});

	registerHook({
		name: 'cimDashboardAfterEntityConfigViewModel',
		func: function(args) {
			var self = args.self;
			var data = args.data;

			var tabsToShow = "";
			// Loop the context tabs and see if it's in the list of tabs to show
			_.each(self.contextTabs(), function(tab) {
				if (_.findIndex(tabsToShow, function(t) {return t == tab.tab.titleText()}) >= 0) {
					tab.show = true;
				} else {
					tab.show = false;
				}
			});
		}
	});
</script>



<div class="gtm-tracking"> 
</div><!-- .gtm-tracking --> 

<div class="ga-ecommerce-tracking">
    <!-- START Tracking/Analytics Code -->
    <!-- END Tracking/Analytics Code -->

</div><!--.ga-ecommerce-tracking --> 
    </body>
</html>