/* Minification failed. Returning unminified contents.
(1967,17-20): run-time error JS1009: Expected '}': ...
(1968,14-15): run-time error JS1009: Expected '}': ;
(1977,43-44): run-time error JS1006: Expected ')': :
(1977,43): run-time error JS1004: Expected ';'
(1977,43-44): run-time error JS1195: Expected expression: :
(1977,54-55): run-time error JS1010: Expected identifier: (
(2004,37-38): run-time error JS1195: Expected expression: .
(2004,85-86): run-time error JS1003: Expected ':': ,
(2005,32-33): run-time error JS1009: Expected '}': :
(1997,33): run-time error JS1004: Expected ';'
(2005,32-33): run-time error JS1195: Expected expression: :
(2005,40-41): run-time error JS1195: Expected expression: .
(2005,92-93): run-time error JS1003: Expected ':': ,
(2006,29): run-time error JS1004: Expected ';'
(2006,29-30): run-time error JS1195: Expected expression: :
(2006,37-38): run-time error JS1195: Expected expression: .
(2006,78-79): run-time error JS1003: Expected ':': ,
(2007,36): run-time error JS1004: Expected ';'
(2007,36-37): run-time error JS1195: Expected expression: :
(2007,44-45): run-time error JS1195: Expected expression: .
(2007,97-98): run-time error JS1003: Expected ':': ,
(2008,25): run-time error JS1004: Expected ';'
(2008,25-26): run-time error JS1195: Expected expression: :
(2008,33-34): run-time error JS1195: Expected expression: .
(2008,48-49): run-time error JS1003: Expected ':': ,
(2010,22): run-time error JS1004: Expected ';'
(2010,22-23): run-time error JS1195: Expected expression: :
(2432,34-37): run-time error JS1009: Expected '}': ...
(2432,33): run-time error JS1004: Expected ';'
(2434,13-14): run-time error JS1002: Syntax error: }
(2437,9-10): run-time error JS1002: Syntax error: }
(2437,10-11): run-time error JS1195: Expected expression: ,
(2443,53-54): run-time error JS1010: Expected identifier: (
(2486,17-20): run-time error JS1009: Expected '}': ...
(2490,9-10): run-time error JS1002: Syntax error: }
(2490,10-11): run-time error JS1195: Expected expression: ,
(2496,48-49): run-time error JS1010: Expected identifier: (
(2508,17-20): run-time error JS1009: Expected '}': ...
(2527,9-10): run-time error JS1002: Syntax error: }
(2527,10-11): run-time error JS1195: Expected expression: ,
(2533,39-40): run-time error JS1010: Expected identifier: (
(2554,10-11): run-time error JS1195: Expected expression: ,
(2560,35-36): run-time error JS1010: Expected identifier: (
(2583,111-112): run-time error JS1195: Expected expression: .
(2583,267-268): run-time error JS1003: Expected ':': ,
(2584,26-27): run-time error JS1009: Expected '}': :
(2573,35): run-time error JS1004: Expected ';'
(2584,26-27): run-time error JS1195: Expected expression: :
(2619,9-10): run-time error JS1002: Syntax error: }
(2619,10-11): run-time error JS1195: Expected expression: ,
(2625,39-40): run-time error JS1010: Expected identifier: (
(2645,17-20): run-time error JS1009: Expected '}': ...
(2649,9-10): run-time error JS1002: Syntax error: }
(2649,10-11): run-time error JS1195: Expected expression: ,
(2651,34-35): run-time error JS1010: Expected identifier: (
(2666,38-39): run-time error JS1195: Expected expression: .
(2666,46-47): run-time error JS1195: Expected expression: .
(2666,55-56): run-time error JS1003: Expected ':': ,
(2672,17-20): run-time error JS1009: Expected '}': ...
(2675,9-10): run-time error JS1002: Syntax error: }
(2675,10-11): run-time error JS1195: Expected expression: ,
(2681,46-47): run-time error JS1010: Expected identifier: (
(2699,17-20): run-time error JS1009: Expected '}': ...
(2706,76-77): run-time error JS1195: Expected expression: .
(2706,81-82): run-time error JS1003: Expected ':': ;
(2712,9-10): run-time error JS1002: Syntax error: }
(2712,10-11): run-time error JS1195: Expected expression: ,
(2718,41-42): run-time error JS1010: Expected identifier: (
(2739,17-20): run-time error JS1009: Expected '}': ...
(2759,9-10): run-time error JS1002: Syntax error: }
(2760,5-6): run-time error JS1002: Syntax error: }
(2792,28-29): run-time error JS1195: Expected expression: .
(2792,35-36): run-time error JS1003: Expected ':': )
(2793,13-18): run-time error JS1009: Expected '}': const
(2793,13-18): run-time error JS1006: Expected ')': const
(2812,5-6): run-time error JS1002: Syntax error: }
(2937,1-2): run-time error JS1002: Syntax error: }
(2937,2-3): run-time error JS1195: Expected expression: )
(3179,108-109): run-time error JS1195: Expected expression: .
(3179,150-151): run-time error JS1003: Expected ':': ;
(4893,73-76): run-time error JS1009: Expected '}': ...
(4893,73-76): run-time error JS1006: Expected ')': ...
(4893,72): run-time error JS1004: Expected ';'
(4893,97): run-time error JS1004: Expected ';'
(4893,97-98): run-time error JS1195: Expected expression: :
(4918,82-85): run-time error JS1009: Expected '}': ...
(4918,82-85): run-time error JS1006: Expected ')': ...
(4918,81): run-time error JS1004: Expected ';'
(4918,100): run-time error JS1004: Expected ';'
(4918,100-101): run-time error JS1195: Expected expression: :
(4919,5-6): run-time error JS1002: Syntax error: }
(4919,6-7): run-time error JS1195: Expected expression: )
(4930,76-79): run-time error JS1009: Expected '}': ...
(4930,76-79): run-time error JS1006: Expected ')': ...
(4930,76): run-time error JS1004: Expected ';'
(4930,94): run-time error JS1004: Expected ';'
(4930,94-95): run-time error JS1195: Expected expression: :
(4931,5-6): run-time error JS1002: Syntax error: }
(4931,6-7): run-time error JS1195: Expected expression: )
(4934,81-84): run-time error JS1009: Expected '}': ...
(4934,81-84): run-time error JS1006: Expected ')': ...
(4934,80): run-time error JS1004: Expected ';'
(4934,99): run-time error JS1004: Expected ';'
(4934,99-100): run-time error JS1195: Expected expression: :
(4935,5-6): run-time error JS1002: Syntax error: }
(4935,6-7): run-time error JS1195: Expected expression: )
(4938,81-84): run-time error JS1009: Expected '}': ...
(4938,81-84): run-time error JS1006: Expected ')': ...
(4938,80): run-time error JS1004: Expected ';'
(4938,99): run-time error JS1004: Expected ';'
(4938,99-100): run-time error JS1195: Expected expression: :
(4939,5-6): run-time error JS1002: Syntax error: }
(4939,6-7): run-time error JS1195: Expected expression: )
(4942,77-80): run-time error JS1009: Expected '}': ...
(4942,77-80): run-time error JS1006: Expected ')': ...
(4942,76): run-time error JS1004: Expected ';'
(4942,95): run-time error JS1004: Expected ';'
(4942,95-96): run-time error JS1195: Expected expression: :
(4943,5-6): run-time error JS1002: Syntax error: }
(4943,6-7): run-time error JS1195: Expected expression: )
(4946,74-77): run-time error JS1009: Expected '}': ...
(4946,74-77): run-time error JS1006: Expected ')': ...
(4946,73): run-time error JS1004: Expected ';'
(4946,92): run-time error JS1004: Expected ';'
(4946,92-93): run-time error JS1195: Expected expression: :
(4947,5-6): run-time error JS1002: Syntax error: }
(4947,6-7): run-time error JS1195: Expected expression: )
(4956,74-77): run-time error JS1009: Expected '}': ...
(4956,74-77): run-time error JS1006: Expected ')': ...
(4956,73): run-time error JS1004: Expected ';'
(4956,92): run-time error JS1004: Expected ';'
(4956,92-93): run-time error JS1195: Expected expression: :
(4957,5-6): run-time error JS1002: Syntax error: }
(4957,6-7): run-time error JS1195: Expected expression: )
(4960,63-66): run-time error JS1009: Expected '}': ...
(4960,63-66): run-time error JS1006: Expected ')': ...
(4960,62): run-time error JS1004: Expected ';'
(4960,81): run-time error JS1004: Expected ';'
(4960,81-82): run-time error JS1195: Expected expression: :
(4961,5-6): run-time error JS1002: Syntax error: }
(4961,6-7): run-time error JS1195: Expected expression: )
(4964,79-82): run-time error JS1009: Expected '}': ...
(4964,79-82): run-time error JS1006: Expected ')': ...
(4964,78): run-time error JS1004: Expected ';'
(4964,97): run-time error JS1004: Expected ';'
(4964,97-98): run-time error JS1195: Expected expression: :
(4965,5-6): run-time error JS1002: Syntax error: }
(4965,6-7): run-time error JS1195: Expected expression: )
(4968,69-72): run-time error JS1009: Expected '}': ...
(4968,69-72): run-time error JS1006: Expected ')': ...
(4968,68): run-time error JS1004: Expected ';'
(4968,87): run-time error JS1004: Expected ';'
(4968,87-88): run-time error JS1195: Expected expression: :
(4969,5-6): run-time error JS1002: Syntax error: }
(4969,6-7): run-time error JS1195: Expected expression: )
(4972,74-77): run-time error JS1009: Expected '}': ...
(4972,74-77): run-time error JS1006: Expected ')': ...
(4972,73): run-time error JS1004: Expected ';'
(4972,92): run-time error JS1004: Expected ';'
(4972,92-93): run-time error JS1195: Expected expression: :
(4973,5-6): run-time error JS1002: Syntax error: }
(4973,6-7): run-time error JS1195: Expected expression: )
(4976,76-79): run-time error JS1009: Expected '}': ...
(4976,76-79): run-time error JS1006: Expected ')': ...
(4976,75): run-time error JS1004: Expected ';'
(4976,94): run-time error JS1004: Expected ';'
(4976,94-95): run-time error JS1195: Expected expression: :
(4977,5-6): run-time error JS1002: Syntax error: }
(4977,6-7): run-time error JS1195: Expected expression: )
(4980,69-72): run-time error JS1009: Expected '}': ...
(4980,69-72): run-time error JS1006: Expected ')': ...
(4980,68): run-time error JS1004: Expected ';'
(4980,87): run-time error JS1004: Expected ';'
(4980,87-88): run-time error JS1195: Expected expression: :
(4981,5-6): run-time error JS1002: Syntax error: }
(4981,6-7): run-time error JS1195: Expected expression: )
(4984,71-74): run-time error JS1009: Expected '}': ...
(4984,71-74): run-time error JS1006: Expected ')': ...
(4984,70): run-time error JS1004: Expected ';'
(4984,89): run-time error JS1004: Expected ';'
(4984,89-90): run-time error JS1195: Expected expression: :
(4985,5-6): run-time error JS1002: Syntax error: }
(4985,6-7): run-time error JS1195: Expected expression: )
(4988,71-74): run-time error JS1009: Expected '}': ...
(4988,71-74): run-time error JS1006: Expected ')': ...
(4988,70): run-time error JS1004: Expected ';'
(4988,89): run-time error JS1004: Expected ';'
(4988,89-90): run-time error JS1195: Expected expression: :
(4989,5-6): run-time error JS1002: Syntax error: }
(4989,6-7): run-time error JS1195: Expected expression: )
(4992,78-81): run-time error JS1009: Expected '}': ...
(4992,78-81): run-time error JS1006: Expected ')': ...
(4992,77): run-time error JS1004: Expected ';'
(4992,96): run-time error JS1004: Expected ';'
(4992,96-97): run-time error JS1195: Expected expression: :
(4993,5-6): run-time error JS1002: Syntax error: }
(4993,6-7): run-time error JS1195: Expected expression: )
(4996,89-92): run-time error JS1009: Expected '}': ...
(4996,89-92): run-time error JS1006: Expected ')': ...
(4996,88): run-time error JS1004: Expected ';'
(4996,107): run-time error JS1004: Expected ';'
(4996,107-108): run-time error JS1195: Expected expression: :
(4997,5-6): run-time error JS1002: Syntax error: }
(4997,6-7): run-time error JS1195: Expected expression: )
(5004,70-73): run-time error JS1009: Expected '}': ...
(5004,70-73): run-time error JS1006: Expected ')': ...
(5004,69): run-time error JS1004: Expected ';'
(5004,88): run-time error JS1004: Expected ';'
(5004,88-89): run-time error JS1195: Expected expression: :
(5005,5-6): run-time error JS1002: Syntax error: }
(5005,6-7): run-time error JS1195: Expected expression: )
(5008,70-73): run-time error JS1009: Expected '}': ...
(5008,70-73): run-time error JS1006: Expected ')': ...
(5008,69): run-time error JS1004: Expected ';'
(5008,88): run-time error JS1004: Expected ';'
(5008,88-89): run-time error JS1195: Expected expression: :
(5009,5-6): run-time error JS1002: Syntax error: }
(5009,6-7): run-time error JS1195: Expected expression: )
(5013,77-80): run-time error JS1009: Expected '}': ...
(5013,77-80): run-time error JS1006: Expected ')': ...
(5013,76): run-time error JS1004: Expected ';'
(5013,95): run-time error JS1004: Expected ';'
(5013,95-96): run-time error JS1195: Expected expression: :
(5014,5-6): run-time error JS1002: Syntax error: }
(5014,6-7): run-time error JS1195: Expected expression: )
(5017,77-80): run-time error JS1009: Expected '}': ...
(5017,77-80): run-time error JS1006: Expected ')': ...
(5017,76): run-time error JS1004: Expected ';'
(5017,95): run-time error JS1004: Expected ';'
(5017,95-96): run-time error JS1195: Expected expression: :
(5018,5-6): run-time error JS1002: Syntax error: }
(5018,6-7): run-time error JS1195: Expected expression: )
(5021,77-80): run-time error JS1009: Expected '}': ...
(5021,77-80): run-time error JS1006: Expected ')': ...
(5021,76): run-time error JS1004: Expected ';'
(5021,95): run-time error JS1004: Expected ';'
(5021,95-96): run-time error JS1195: Expected expression: :
(5022,5-6): run-time error JS1002: Syntax error: }
(5022,6-7): run-time error JS1195: Expected expression: )
(5025,80-83): run-time error JS1009: Expected '}': ...
(5025,80-83): run-time error JS1006: Expected ')': ...
(5025,79): run-time error JS1004: Expected ';'
(5025,98): run-time error JS1004: Expected ';'
(5025,98-99): run-time error JS1195: Expected expression: :
(5026,5-6): run-time error JS1002: Syntax error: }
(5026,6-7): run-time error JS1195: Expected expression: )
(5030,80-83): run-time error JS1009: Expected '}': ...
(5030,80-83): run-time error JS1006: Expected ')': ...
(5030,79): run-time error JS1004: Expected ';'
(5030,98): run-time error JS1004: Expected ';'
(5030,98-99): run-time error JS1195: Expected expression: :
(5031,5-6): run-time error JS1002: Syntax error: }
(5031,6-7): run-time error JS1195: Expected expression: )
(5034,80-83): run-time error JS1009: Expected '}': ...
(5034,80-83): run-time error JS1006: Expected ')': ...
(5034,79): run-time error JS1004: Expected ';'
(5034,98): run-time error JS1004: Expected ';'
(5034,98-99): run-time error JS1195: Expected expression: :
(5035,5-6): run-time error JS1002: Syntax error: }
(5035,6-7): run-time error JS1195: Expected expression: )
(5038,80-83): run-time error JS1009: Expected '}': ...
(5038,80-83): run-time error JS1006: Expected ')': ...
(5038,79): run-time error JS1004: Expected ';'
(5038,98): run-time error JS1004: Expected ';'
(5038,98-99): run-time error JS1195: Expected expression: :
(5039,5-6): run-time error JS1002: Syntax error: }
(5039,6-7): run-time error JS1195: Expected expression: )
(5042,80-83): run-time error JS1009: Expected '}': ...
(5042,80-83): run-time error JS1006: Expected ')': ...
(5042,79): run-time error JS1004: Expected ';'
(5042,98): run-time error JS1004: Expected ';'
(5042,98-99): run-time error JS1195: Expected expression: :
(5043,5-6): run-time error JS1002: Syntax error: }
(5043,6-7): run-time error JS1195: Expected expression: )
(5046,80-83): run-time error JS1009: Expected '}': ...
(5046,80-83): run-time error JS1006: Expected ')': ...
(5046,79): run-time error JS1004: Expected ';'
(5046,98): run-time error JS1004: Expected ';'
(5046,98-99): run-time error JS1195: Expected expression: :
(5047,5-6): run-time error JS1002: Syntax error: }
(5047,6-7): run-time error JS1195: Expected expression: )
(5050,80-83): run-time error JS1009: Expected '}': ...
(5050,80-83): run-time error JS1006: Expected ')': ...
(5050,79): run-time error JS1004: Expected ';'
(5050,98): run-time error JS1004: Expected ';'
(5050,98-99): run-time error JS1195: Expected expression: :
(5051,5-6): run-time error JS1002: Syntax error: }
(5051,6-7): run-time error JS1195: Expected expression: )
(5054,80-83): run-time error JS1009: Expected '}': ...
(5054,80-83): run-time error JS1006: Expected ')': ...
(5054,79): run-time error JS1004: Expected ';'
(5054,98): run-time error JS1004: Expected ';'
(5054,98-99): run-time error JS1195: Expected expression: :
(5055,5-6): run-time error JS1002: Syntax error: }
(5055,6-7): run-time error JS1195: Expected expression: )
(5058,80-83): run-time error JS1009: Expected '}': ...
(5058,80-83): run-time error JS1006: Expected ')': ...
(5058,79): run-time error JS1004: Expected ';'
(5058,98): run-time error JS1004: Expected ';'
(5058,98-99): run-time error JS1195: Expected expression: :
(5059,5-6): run-time error JS1002: Syntax error: }
(5059,6-7): run-time error JS1195: Expected expression: )
(5062,80-83): run-time error JS1009: Expected '}': ...
(5062,80-83): run-time error JS1006: Expected ')': ...
(5062,79): run-time error JS1004: Expected ';'
(5062,98): run-time error JS1004: Expected ';'
(5062,98-99): run-time error JS1195: Expected expression: :
(5063,5-6): run-time error JS1002: Syntax error: }
(5063,6-7): run-time error JS1195: Expected expression: )
(5066,80-83): run-time error JS1009: Expected '}': ...
(5066,80-83): run-time error JS1006: Expected ')': ...
(5066,79): run-time error JS1004: Expected ';'
(5066,98): run-time error JS1004: Expected ';'
(5066,98-99): run-time error JS1195: Expected expression: :
(5067,5-6): run-time error JS1002: Syntax error: }
(5067,6-7): run-time error JS1195: Expected expression: )
(5071,79-82): run-time error JS1009: Expected '}': ...
(5071,79-82): run-time error JS1006: Expected ')': ...
(5071,78): run-time error JS1004: Expected ';'
(5071,97): run-time error JS1004: Expected ';'
(5071,97-98): run-time error JS1195: Expected expression: :
(5072,5-6): run-time error JS1002: Syntax error: }
(5072,6-7): run-time error JS1195: Expected expression: )
(5074,79-82): run-time error JS1009: Expected '}': ...
(5074,79-82): run-time error JS1006: Expected ')': ...
(5074,78): run-time error JS1004: Expected ';'
(5074,97): run-time error JS1004: Expected ';'
(5074,97-98): run-time error JS1195: Expected expression: :
(5075,5-6): run-time error JS1002: Syntax error: }
(5075,6-7): run-time error JS1195: Expected expression: )
(5078,79-82): run-time error JS1009: Expected '}': ...
(5078,79-82): run-time error JS1006: Expected ')': ...
(5078,78): run-time error JS1004: Expected ';'
(5078,97): run-time error JS1004: Expected ';'
(5078,97-98): run-time error JS1195: Expected expression: :
(5079,5-6): run-time error JS1002: Syntax error: }
(5079,6-7): run-time error JS1195: Expected expression: )
(5082,79-82): run-time error JS1009: Expected '}': ...
(5082,79-82): run-time error JS1006: Expected ')': ...
(5082,78): run-time error JS1004: Expected ';'
(5082,97): run-time error JS1004: Expected ';'
(5082,97-98): run-time error JS1195: Expected expression: :
(5083,5-6): run-time error JS1002: Syntax error: }
(5083,6-7): run-time error JS1195: Expected expression: )
(5086,79-82): run-time error JS1009: Expected '}': ...
(5086,79-82): run-time error JS1006: Expected ')': ...
(5086,78): run-time error JS1004: Expected ';'
(5086,97): run-time error JS1004: Expected ';'
(5086,97-98): run-time error JS1195: Expected expression: :
(5087,5-6): run-time error JS1002: Syntax error: }
(5087,6-7): run-time error JS1195: Expected expression: )
(5090,79-82): run-time error JS1009: Expected '}': ...
(5090,79-82): run-time error JS1006: Expected ')': ...
(5090,78): run-time error JS1004: Expected ';'
(5090,97): run-time error JS1004: Expected ';'
(5090,97-98): run-time error JS1195: Expected expression: :
(5091,5-6): run-time error JS1002: Syntax error: }
(5091,6-7): run-time error JS1195: Expected expression: )
(5095,74-77): run-time error JS1009: Expected '}': ...
(5095,74-77): run-time error JS1006: Expected ')': ...
(5095,73): run-time error JS1004: Expected ';'
(5095,92): run-time error JS1004: Expected ';'
(5095,92-93): run-time error JS1195: Expected expression: :
(5096,5-6): run-time error JS1002: Syntax error: }
(5096,6-7): run-time error JS1195: Expected expression: )
(5099,74-77): run-time error JS1009: Expected '}': ...
(5099,74-77): run-time error JS1006: Expected ')': ...
(5099,73): run-time error JS1004: Expected ';'
(5099,92): run-time error JS1004: Expected ';'
(5099,92-93): run-time error JS1195: Expected expression: :
(5100,5-6): run-time error JS1002: Syntax error: }
(5100,6-7): run-time error JS1195: Expected expression: )
(5103,74-77): run-time error JS1009: Expected '}': ...
(5103,74-77): run-time error JS1006: Expected ')': ...
(5103,73): run-time error JS1004: Expected ';'
(5103,92): run-time error JS1004: Expected ';'
(5103,92-93): run-time error JS1195: Expected expression: :
(5104,5-6): run-time error JS1002: Syntax error: }
(5104,6-7): run-time error JS1195: Expected expression: )
(5107,74-77): run-time error JS1009: Expected '}': ...
(5107,74-77): run-time error JS1006: Expected ')': ...
(5107,73): run-time error JS1004: Expected ';'
(5107,92): run-time error JS1004: Expected ';'
(5107,92-93): run-time error JS1195: Expected expression: :
(5108,5-6): run-time error JS1002: Syntax error: }
(5108,6-7): run-time error JS1195: Expected expression: )
(5111,74-77): run-time error JS1009: Expected '}': ...
(5111,74-77): run-time error JS1006: Expected ')': ...
(5111,73): run-time error JS1004: Expected ';'
(5111,92): run-time error JS1004: Expected ';'
(5111,92-93): run-time error JS1195: Expected expression: :
(5112,5-6): run-time error JS1002: Syntax error: }
(5112,6-7): run-time error JS1195: Expected expression: )
(5115,74-77): run-time error JS1009: Expected '}': ...
(5115,74-77): run-time error JS1006: Expected ')': ...
(5115,73): run-time error JS1004: Expected ';'
(5115,92): run-time error JS1004: Expected ';'
(5115,92-93): run-time error JS1195: Expected expression: :
(5116,5-6): run-time error JS1002: Syntax error: }
(5116,6-7): run-time error JS1195: Expected expression: )
(5119,80-83): run-time error JS1009: Expected '}': ...
(5119,80-83): run-time error JS1006: Expected ')': ...
(5119,79): run-time error JS1004: Expected ';'
(5120,5-6): run-time error JS1002: Syntax error: }
(5120,6-7): run-time error JS1195: Expected expression: )
(5123,81-84): run-time error JS1009: Expected '}': ...
(5123,81-84): run-time error JS1006: Expected ')': ...
(5123,80): run-time error JS1004: Expected ';'
(5124,5-6): run-time error JS1002: Syntax error: }
(5124,6-7): run-time error JS1195: Expected expression: )
(5127,80-83): run-time error JS1009: Expected '}': ...
(5127,80-83): run-time error JS1006: Expected ')': ...
(5127,79): run-time error JS1004: Expected ';'
(5128,5-6): run-time error JS1002: Syntax error: }
(5128,6-7): run-time error JS1195: Expected expression: )
(5131,84-87): run-time error JS1009: Expected '}': ...
(5131,84-87): run-time error JS1006: Expected ')': ...
(5131,83): run-time error JS1004: Expected ';'
(5132,5-6): run-time error JS1002: Syntax error: }
(5132,6-7): run-time error JS1195: Expected expression: )
(5220,1-2): run-time error JS1002: Syntax error: }
(5220,2-3): run-time error JS1195: Expected expression: )
(2612,21-27): run-time error JS1018: 'return' statement outside of function: return
(2605,21-27): run-time error JS1018: 'return' statement outside of function: return
(2218,25-31): run-time error JS1018: 'return' statement outside of function: return
(2413,17-23): run-time error JS1018: 'return' statement outside of function: return
 */
/* eslint-disable */
// Array.find
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
    Object.defineProperty(Array.prototype, "find", {
        value: function (predicate) {
            // 1. Let O be ? ToObject(this value).
            if (this == null) {
                throw new TypeError('"this" is null or not defined');
            }

            var o = Object(this);

            // 2. Let len be ? ToLength(? Get(O, "length")).
            var len = o.length >>> 0;

            // 3. If IsCallable(predicate) is false, throw a TypeError exception.
            if (typeof predicate !== "function") {
                throw new TypeError("predicate must be a function");
            }

            // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
            var thisArg = arguments[1];

            // 5. Let k be 0.
            var k = 0;

            // 6. Repeat, while k < len
            while (k < len) {
                // a. Let Pk be ! ToString(k).
                // b. Let kValue be ? Get(O, Pk).
                // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
                // d. If testResult is true, return kValue.
                var kValue = o[k];
                if (predicate.call(thisArg, kValue, k, o)) {
                    return kValue;
                }
                // e. Increase k by 1.
                k++;
            }

            // 7. Return undefined.
            return undefined;
        },
        configurable: true,
        writable: true
    });
}

// Object.assign
// added to decouple us from $.extend
if (typeof Object.assign !== "function") {
    // Must be writable: true, enumerable: false, configurable: true
    Object.defineProperty(Object, "assign", {
        value: function assign(target, varArgs) { // .length of function is 2
            "use strict";
            if (target == null) { // TypeError if undefined or null
                throw new TypeError("Cannot convert undefined or null to object");
            }

            var to = Object(target);

            for (var index = 1; index < arguments.length; index++) {
                var nextSource = arguments[index];

                if (nextSource != null) { // Skip over if undefined or null
                    for (var nextKey in nextSource) {
                        // Avoid bugs when hasOwnProperty is shadowed
                        if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
                            to[nextKey] = nextSource[nextKey];
                        }
                    }
                }
            }
            return to;
        },
        writable: true,
        configurable: true
    });
}



// Object.entries
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill
// dependent on Object.keys (we don't support IE9
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.entries) {
    Object.entries = function (obj) {
        var ownProps = Object.keys(obj),
            i = ownProps.length,
            resArray = new Array(i); // preallocate the Array
        while (i--)
            resArray[i] = [ownProps[i], obj[ownProps[i]]];

        return resArray;
    };
}

if (!String.prototype.endsWith) {
    String.prototype.endsWith = function (search, this_len) {
        if (this_len === undefined || this_len > this.length) {
            this_len = this.length;
        }
        return this.substring(this_len - search.length, this_len) === search;
    };
}

if (!Array.prototype.includes) {
    Array.prototype.includes = function (term) {
        return (this.indexOf(term) !== -1);
    };
}


/* eslint-enable */;
; (function (wts, modules) {
    "use strict";

    //
    // utilities that help keep our code cleaner
    //

    var _ = modules.utilities = {

        FORBIDDEN_SYMBOLS : /[[\]*{}^<>!?\\;=|~]+/g,

        /**
         * Returns the input value — useful as a functional predicate
         * @param {any} value the data passed to this fn, if any
         * @returns {any} the argument value
         */
        identity: function (value) {
            return value;
        },

        // returns true|false 
        isNullOrUndefined: function (input) {
            return (input === null || typeof input === "undefined");
        },

        // returns true|false 
        isNumber: function (input) {
            return $.isNumeric(input);
        },

        // returns true|false 
        isInteger: function (input) {
            return _.isNumber(input) && (input === Math.round(input));
        },

        /**
         * @description Binds all functions of an object (and it's prototype) to the context of the object.
         * @param {object} obj - an object containing function members
         * @param {object} [scope=undefined] - scope in which the target members will be bound
         * @param {string[]} [exceptions=undefined] - a string list of function names that should not be bound
         * @returns {undefined}
         */
        bindAll: function (obj, scope, exceptions) {

            var scopeParam = (typeof scope === "undefined" ? obj : scope);
            var exceptionsParam = exceptions || [];

            var keys = [];
            for (var key in obj) keys.push(key); // eslint-disable-line

            keys
                .filter(function (k) {
                    return exceptionsParam.indexOf(k) < 0;
                })
                .forEach(function (k) {
                    if (typeof obj[k] === "function") obj[k] = obj[k].bind(scopeParam);
                });
        },

        /**
         * @description Returns a function, that, as long as it continues to be invoked, will not be triggered.
         * The function will be called after it stops being called for N milliseconds. If `immediate` is passed, trigger the
         * function on the leading edge, instead of the trailing.
         * @param {Function} func - function to debounce
         * @param {number} wait time that must pass without an additional call, in milliseconds
         * @param {boolean} [immediate=undefined] - immediate Whether the callback should be called on the leading edge of debouncing
         * @see https://davidwalsh.name/javascript-debounce-function
         * @returns {CallableFunction} returns the debounced function
         */
        debounce: function (func, wait, immediate) {
            var timeout = null;
            function run() {
                var context = this;
                var args = arguments;

                var later = function () {
                    timeout = null;
                    if (!immediate) {
                        func.apply(context, args);
                    }
                };

                var callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) {
                    func.apply(context, args);
                }
            };

            run.cancel = function () {
                if (timeout !== null) {
                    clearTimeout(timeout);
                    timeout = null;
                }
            };

            return run;
        },

        /**
         * Scroll the viewport to a specific element
         * @param {jQuery|HTMLElement} element The element to scroll to
         * @param {int} duration A duration to scroll, in milliseconds
         * @returns {undefined}
         */
        scrollToElement: function (element, duration) {

            var $element = null;

            if (!($element instanceof window.jQuery)) {
                $element = $(element);
            }
            else {
                $element = element;
            }

            $("html, body").animate({
                scrollTop: $element.offset().top
            }, duration);
        },

        /**
         * Defers a function to be called at the "next tick".
         * @param {Function} fn A function that can be called
         * @returns {int} An ID for calling window.cancelTimeout
         * @todo Update this to return a deferred function, instead of immediately deferring
         */
        defer: function (fn) {
            return window.setTimeout(fn, 0);
        },

        /**
         * Decodes HTML via jQuery
         * @param {string} text Text to be decoded
         * @returns {string} the decoded text
         * @see http://stackoverflow.com/questions/1219860/html-encoding-in-javascript-jquery
         */
        encodeHTML: function (text) {
            if (text === null) {
                return null;
            }

            return text
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&apos;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;");
        },

        /**
         * Decodes HTML via jQuery
         * @param {string} text Text to be decoded
         * @returns {string} the decoded text
         */
        decodeHTML: function (text) {
            return $("<div />").html(text).text();
        },

        /**
         * Escapes HTML via jQuery
         * @param {string} text Text to be escaped
         * @returns {string} Text that is escaped
         */
        escapeHTML: function (text) {
            return $("<div/>").text(text).html();
        },

        /**
         * Retrieves a truck's ID from the DOM, likely for use on VSP
         * @param {HTMLElement} element An element representing the .truck component or one if its children
         * @returns {string|null} The truck ID, or null
         */
        getTruckID: function (element) {
            var $truck = $(element).closest(".truck");
            return $truck.data("truck-id") || null;
        },

        /**
         * Retrieves a query string parameter by name
         * @todo This methodology doesn't properly accomodate for multiple items per name
         * @param {string} name The key to look for in the search
         * @returns {string|null} The query parameter, as a string or null
         */
        getQueryParameter: function (name) {
            var search = window.location.search.substring(1);
            if (search.length === 0) {
                return null;
            }

            var parts = search.split("&");
            var queryStringParams = parts.reduce(function (map, part, i) {
                var keyValue = part[i].split("=");
                var key = keyValue[0];
                var value = keyValue[1];

                map[key] = value;

                return map;
            }, {});

            var hasValue = typeof queryStringParams[name] === undefined;
            return hasValue ? null : queryStringParams[name];
        },

        /**
         * Convenience method for building a selector string for matching a name attribute
         * General usage is to then pass the result to a jQuery selector 
         * @remarks This might be better as a jQuery plugin
         * @param {string} [parent=undefined] A selector string representing a parent of a target element `.parent [name="name"]`
         * @param {string} [selector=undefined] A selector string for prepending to the name selector `.parent .selector[name="name"]`
         * @param {string} name The name of the element
         * @returns {string} The selector string
         */
        nameSelector: function (/* [parent, selector,] name */) {

            var parent = "";
            var selector = "";
            var name = "";

            switch (arguments.length) {
                case 1:
                    name = arguments[0];
                    break;

                case 2:
                    selector = arguments[0];
                    name = arguments[1];
                    break;

                case 3:
                    parent = arguments[0];
                    selector = arguments[1];
                    name = arguments[2];
                    break;
            }

            return (parent + " " + selector + "[name='" + name + "']");
        },

        /**
         *  Retrieves the truck title text and photo from a vehicle listing
         *  Previously named "GetTruckListingTitleAndPhoto" in _InventoryLayout.cshtml
         *  @param {jQuery} $listing The truck listing in which a truck title and photo are being retrieved from
         *  @returns {any} An object containing "title" and "image" fields
         *                 representing title text and img src of the vehicle
         */
        getTruckTitleAndPhoto: function ($listing) {
            
            var $image = $listing.find(".truck-image__image");

            // CASE: because of lazy-loading library which uses data-src, the attribute "src" may 
            // not be set on page load, so we fallback to the src property (as assigned by lazy-load)
            // or the data-src attribute, which lazy-load would load.
            var imageSrc = $image.attr("src") || $image.prop("src") || $image.attr("data-src");

            return {
                title: $listing.find(".truck__link-text").text().trim(),
                image: imageSrc,
                truckID: $listing.data('truckId')
            };
        },

        /**
         *  Parse a phone string for display: (530) 123-4567, Ext. 890
         *  (this frontend method mirrors the logic of the WTSUtils.StringUtils.ParseForPhoneDisplay backend method)
         *  @param {string} phoneNo The phone no.
         *  @returns {string} A formatted phone number
         */
        parseForPhoneDisplay: function (phoneNo) {

            if (!phoneNo) {
                return "";
            }

            let parts = this.parsePhoneString(phoneNo);
            let telPhoneCode = "";

            if (parts.isValid) {
                if (parts.extension) {
                    telPhoneCode = `(${parts.area}) ${parts.prefix}-${parts.suffix}, Ext. ${parts.extension}`;
                }
                else {
                    telPhoneCode = `(${parts.area}) ${parts.prefix}-${parts.suffix}`;
                }
            }

            return telPhoneCode;
        },

        /**
         *  Parse the phone string into its parts.
         *  @param {string} phoneNo The phone no.
         *  @returns {PhoneParts} A JavaScript object containing the parsed area code, 
         *  prefix, suffix, and extension of the provided phone number
         */
        parsePhoneString: function (phoneNo) {
            /**
            *  @class PhoneParts
            *  @type {Object}
            *  @property {boolean} isValid
            *  @property {string} area The phone number area code.
            *  @property {string} prefix The phone number prefix.
            *  @property {string} suffix The phone number suffix.
            *  @property {string} extension The phone number extension.
            */
            class PhoneParts {
                constructor(isValid, area, prefix, suffix, extension) {
                    this.isValid = isValid;
                    this.area = area;
                    this.prefix = prefix;
                    this.suffix = suffix;
                    this.extension = extension;
                }
            }

            const phoneDigitsRegex = new RegExp("[^0-9\\x]");

            if (!phoneNo) {
                return new PhoneParts(false, "", "", "", "");
            }

            // Remove everything but numerals and the x
            let cleanString = phoneNo.replace(phoneDigitsRegex, "");

            // If phoneNo started with 1 or 0 then 'x' will end up in the wrong position,
            // so we'll just remove it and parse the remaining digits. 
            // 7-digit numbers are a thing of the past. Phone field validation rejects anything 
            // less than 10 digits, so the position of the 'x' is not important and could be problematic
            cleanString = cleanString.replace("x", "");

            // There are no U.S. area codes (or prefixes) that start with 1 (or 0), so let's get rid of those leading digits.
            if (cleanString.startsWith("0")) {
                // We really can't guess what the number should be, so just bail out
                return new PhoneParts(false, "", "", "", "");
            }

            while (cleanString.startsWith("1")) {
                // Here a leading 1 is probably just a bad habit taught by thousands of companies that think their users 
                // don't know how to use a phone ... in an era when most calls are mobile and don't need to start with 1.
                cleanString = cleanString.substring(1);
            }

            // Now let's get the extension
            let extension = null;

            if (cleanString.length > 10) {
                // get the extension
                extension = cleanString.substring(10);

                // remove the extension from original string
                cleanString = cleanString.substring(0, 10);
            }

            if (cleanString.length == 10) {
                let area = cleanString.substring(0, 3);
                let prefix = cleanString.substring(3, 6);
                let suffix = cleanString.substring(6, 10);

                return new PhoneParts(true, area, prefix, suffix, extension);
            }

            // Anything else is not valid
            return new PhoneParts(false, "", "", "", "");
        },

        /**
         * Detect if a containing HTMLElement has content overflow on either axis
         * @param {jQuery|HTMLElement} element The element whose content overflow status you want to check
         * @returns {boolean}
         */
        hasContentOverflow: function (element) {
            var $element = null;

            if (!($element instanceof window.jQuery)) {
                $element = $(element);
            }
            else {
                $element = element;
            }

            return $element.prop('scrollWidth') > $element.width() || $element.prop('scrollHeight') > $element.height()
        },

        hasForbiddenSymbols: function(str) {
            return str.match(_.FORBIDDEN_SYMBOLS) !== null;
        },

        /**
         * Helper function used to get the text of the innermost html element. Helpful when the text of "what" was clicked is needed.
         * @param {any} $element the element to get the innermost text from.
         * @returns {string} The inner text of the element.
         */
        getInnerText: function ($el) {
            var $innermostChild = $el;
            var $next = $innermostChild;

            do {
                $innermostChild = $next;
                $next = $next.children();
            } while ($next.length);

            return $innermostChild.html().trim();
        },

        /**
         * Helper function used to get the appropriate carousel description
         * @param {any} $el The item within the carousel to resolve a desciption for.
         * @returns Either "similar-vehicle-carousel" OR "recently-viewed-carousel", depending on which carousel was resolved from $el.
         */
        getCarouselDescription: function ($el) {
            var $carousel = $el.parents(".wts-vehicle-carousel--similar-vehicles-carousel")

            if ($carousel.length) {
                return "similar-vehicle-carousel";
            } else {
                var $carousel = $el.parents(".wts-vehicle-carousel--recently-viewed-carousel")
                if (!$carousel.length) {
                    // parent carousel not found so return nothing
                    return;
                }

                return "recently-viewed-carousel";
            }
        }
    };

})(window.wts, window.wts.modules);
;
; (function (wts, modules) {

    // this is the correct mime type we expect for these
    var utilities = modules.utilities;
    var mimeType = "application/json";
    var cache = Object.create(null);

    /**
     * Finds and parses the JSON script tag associated to the selector parameter, or returns null
     * @param {string} selector The DOMString corrosponding to the id of the <script> tag to find
     * @throws {DOMException} Upon an invalid selector
     * @throws {Error} Upon reading a script with an incorrect mime-type — should be "application/json"
     * @returns {any} The result of parsing the script tag
     */
    modules.getClientData = function (selector) {

        // repeated calls don't reparse the JSON
        if (!utilities.isNullOrUndefined(cache[selector])) {
            return cache[selector];
        }

        var scriptEl = document.querySelector(selector);

        // enforce us to not incorrectly attaching running-code
        if (scriptEl !== null && scriptEl.type.toLowerCase() !== mimeType) {
            throw new Error("Script corresponding to '" + selector + "' is not of type '" + mimeType + "'");
        }

        if (scriptEl === null) {
            return null;
        }

        var data = null;

        try {
            data = JSON.parse(scriptEl.innerText);
        }
        catch (ex) {
            console.error(ex);
        }

        cache[selector] = data;

        return data;
    };


})(window.wts, window.wts.modules);;
/**
 * @module EventEmitter
 */
; (function (wts, modules) {
    "use strict";

    var WILDCARD_CHAR = "*";

    /** 
     * @description A custom, cross-browser compliant event-emitter. Useful for implementing modules with observer-like
     * patterns (listeners). Not meant to be used for DOM-related events, meant for higher-level events.
     * @constructor
     * @type {IEventEmitter}
     * @example 
     * var events = new EventEmitter();
     * events.on("module:initialized", function(event){ console.log(event) });
     * // then, somewhere else in the code...
     * events.trigger("module:initialized", { data });
     * events.off("module:initialized") // clear all listeners
     */
    function EventEmitter() {

        /**
         * @this {IEventEmitter}
         */
        this._listeners = Object.create(null);
        ;[
            "addEventListener",
            "removeEventListener",
            "dispatchEvent",
            "on",
            "off",
            "trigger",
            "clear"
        ].forEach(function (fn) {
            this[fn] = this[fn].bind(this);
        }, this);

    }

    EventEmitter.prototype = {

        /**
         * @description Adds a new listener that will be be called when parameter event <type> is dispatched
         * @param {string} type The name of an event to listen for
         * @param {EventListenerCallback} callback The function that will be called when the event is fired
         * @param {object|undefined} [context=undefined] The context that the function will be called with—in effect: `callback.call(context);`
         * @throws {Error}
         * @returns {Function} The function for unlistening to this event listener
         */
        addEventListener: function (type, callback, context) {
            if (typeof type !== "string") {
                throw new Error("EventEmitter.addEventListener: argument 0 must be a string.");
            }

            if (typeof callback === "undefined") {
                throw new Error("EventEmitter.addEventListener: argument 1 must be a function.");
            }

            var that = this;
            this._listeners[type] = this._listeners[type] || [];
            /**
             * @var listener
             * @type {IEventListener}
             */
            var listener = {
                type: type,
                callback: callback,
                context: context || null,
                cancel: function () {
                    that.removeEventListener(type, callback);
                }
            };

            this._listeners[type].push(listener);

            return listener.cancel;
        },

        /**
         * @description Removes a previously-defined listener
         * @param {string} type
         * @param {EventListenerCallback} callback
         * @returns {IEventEmitter}
         */
        removeEventListener: function (type, callback) {

            if (typeof type !== "string") {
                throw new Error("EventEmitter.removeEventListener: argument 0 must be a string.");
            }

            // if callback is not provided, clear all listeners for that event
            if (typeof callback === "undefined") {
                this._listeners[type] = [];
            }
            else {

                var eventList = (this._listeners[type] || []);
                // remove the event
                this._listeners[type] = eventList.filter(function (listener, i) {
                    return (listener.callback !== callback);
                });
            }
            return this;
        },

        /**
         * @description Clears ALL event listeners
         */
        clear: function () {
            this._listeners = Object.create(null);
        },

        /**
         * @description Fires an event with the parameter type and data.
         * @param {string} type The event name to dispatch
         * @param {EventListenerData} [data=null] - Any additional data to be passed to the event callback
         * @returns {IEventListener[]} - An array of all the listener callbacks that were fired
         */
        dispatchEvent: function (type, data) {

            var timestamp = Date.now();
            var listeners = (this._listeners[type] || []);

            var wildcards = this._listeners[WILDCARD_CHAR] || [];

            return listeners.concat(wildcards).map(function (event) {
                var eventDetails = {
                    type: type,
                    context: event.context,
                    data: typeof data === "undefined" ? null : data,
                    timestamp: timestamp
                };

                return event.callback.call(event.context, eventDetails);
            });
        },

        /**
         * @alias addEventListener
         * @param {[string, EventListenerCallback]|[string, EventListenerCallback, EventListenerContext]} arguments
         * @returns {IEventEmitter}
         */
        on: function () {
            return this.addEventListener.apply(this, arguments);
        },

        /**
         * @alias removeEventListener
         * @param {[string, EventListenerCallback]} arguments
         * @returns {IEventEmitter}
         */
        off: function () {
            return this.removeEventListener.apply(this, arguments);
        },

        /**
         * @alias dispatchEvent
         * @param {[string]|[string, EventListenerData]} arguments
         * @returns {IEventListener[]} list of callbacks triggered
         */
        trigger: function () {
            return this.dispatchEvent.apply(this, arguments);
        },

        /**
         * Add a listener that will only fire once
         * @param {string} type The name of an event to listen for
         * @param {EventListenerCallback} callback The function that will be called when the event is fired
         * @param {EventListenerContext} [context=null] The context that the function will be called with—in effect: `callback.call(context);`
         * @returns {Function} A function to cancel listening to the event
         */
        once: function (type, callback, context) {

            var removeCallback = this.on(type, function () {
                callback.apply(context, arguments);
                removeCallback();
            }, context);

            return removeCallback;
        }
    };


    modules.EventEmitter = EventEmitter;

})(window.wts, window.wts.modules);
;

window.wts.UI_EVENTS = {

    /**
     * When a user views a page — initial page views can be handled by analytics libraries
     * This event exists for pages loaded after the initial page view—such as truck search's search results.
     */
    PAGE_VIEW: "PAGE_VIEW",

    /**
     * Fired from the document ready function of a page.  Intended to be fired when a page has loaded.
     */
    PAGE_LOAD: "PAGE_LOAD",

    /**
     * Fired from various places within the UI when the user interacts with something on the page that triggers navigation or progression
     * to a new state.
     */
    INTERACTION_CLICK: "INTERACTION_CLICK",

    /**
     * Fired when the "See All Photos" link is clicked.
     */
    SEE_MORE_INTERACTION_CLICK: "SEE_MORE_INTERACTION_CLICK",

    /**
     * Handles interaction click events fired from controls targeted in the _Layout.cshtml file.
     */
    GENERAL_LAYOUT_INTERACTION_CLICK: "GENERAL_LAYOUT_INTERACTION_CLICK",

    /**
     * Fired when the vocational carousel changes pages.
     */
    VOCATIONAL_CAROUSEL_PAGE_CHANGE: "VOCATIONAL_CAROUSEL_PAGE_CHANGE",

    /**
     * Fired when either the items per page or sort by from the top/bottom navs changes.
     */
    PAGINATION_CONTROL_CHANGE: "PAGINATION_CONTROL_CHANGE",

    /**
     * Fired from various places within the UI when the user interacts with a form for the first time (presently only I'm Interested).
     */
    FORM_START: "FORM_START",

    /**
     * Fired when a form's contents change.
     */
    FORM_ENGAGE: "FORM_ENGAGE",

    /**
     * Clicking I'm interested generally should fire this
     */
    OPEN_VEHICLE_INQUIRY_FORM: "OPEN_VEHICLE_INQUIRY_FORM",

    /**
     * Submitting most "lead"-generating forms
     */
    SUBMIT_VEHICLE_INQUIRY_FORM: "SUBMIT_VEHICLE_INQUIRY_FORM",

    /**
     * An error occurred submitting most "lead"-generating forms
     */
    SUBMIT_VEHICLE_INQUIRY_FORM_ERROR: "SUBMIT_VEHICLE_INQUIRY_FORM_ERROR",

    /**
     * Submitting the load garage form
     **/
    SUBMIT_LOAD_GARAGE_FORM: "SUBMIT_LOAD_GARAGE_FORM",

    /**
     * Submitting the custom form
     **/
    SUBMIT_CUSTOM_FORM: "SUBMIT_CUSTOM_FORM",

    /** 
     * The user has waited for the end of a form submission
     */
    WAIT_FOR_FORM_CONFIRMATION: "WAIT_FOR_FORM_CONFIRMATION",

    /**
     * Clicking the support link
     */
    CLICK_SUPPORT_LINK: "CLICK_SUPPORT_LINK",

    /**
     * Clicking call us now from the I'm Interested modal
     */
    CALL_US_NOW_IM_INTERESTED: "CALL_US_NOW_IM_INTERESTED",

    /**
     * Clicking the 'Request a Callback' button in the Call Us modal
     */
    CALLBACK_REQUEST_CLICK: "CALLBACK_REQUEST_CLICK",

    /**
     * Interactions that open the photo gallery
     */
    PHOTO_GALLERY_OPEN: "PHOTO_GALLERY_OPEN",

    /**
     * Interactions that close the photo gallery
     */
    PHOTO_GALLERY_CLOSE: "PHOTO_GALLERY_CLOSE",

    /**
     * Within the Photo Gallery, interactions that view the next photo
     */
    PHOTO_GALLERY_NEXT_PHOTO: "PHOTO_GALLERY_NEXT_PHOTO",

    /**
     * Within the Photo Gallery, interactions that view the previous photo
     */
    PHOTO_GALLERY_PREVIOUS_PHOTO: "PHOTO_GALLERY_PREVIOUS_PHOTO",

    /**
     * Within the Photo Gallery, interactions that view the next page of thumbnails
     */
    PHOTO_GALLERY_NEXT_PAGE: "PHOTO_GALLERY_NEXT_PAGE",

    /**
    * Within the Photo Gallery, interactions that view the previous page of thumbnails
    */
    PHOTO_GALLERY_PREVIOUS_PAGE: "PHOTO_GALLERY_PREVIOUS_PAGE",

    /**
     * Within the Photo Gallery, interactions that view the next photo
     */
    FEATURED_PHOTO_GALLERY_NEXT_PHOTO: "FEATURED_PHOTO_GALLERY_NEXT_PHOTO",

    /**
     * Within the Photo Gallery, interactions that view the previous photo
     */
    FEATURED_PHOTO_GALLERY_PREVIOUS_PHOTO: "FEATURED_PHOTO_GALLERY_PREVIOUS_PHOTO",

    /**
     * Within the Photo Gallery, interactions that view the next page of thumbnails
     */
    FEATURED_PHOTO_GALLERY_NEXT_PAGE: "FEATURED_PHOTO_GALLERY_NEXT_PAGE",

    /**
    * Within the Photo Gallery, interactions that view the previous page of thumbnails
    */
    FEATURED_PHOTO_GALLERY_PREVIOUS_PAGE: "FEATURED_PHOTO_GALLERY_PREVIOUS_PAGE",

    /**
     * Within the Photo Gallery, clicking a thumbnail
     */
    PHOTO_GALLERY_CLICK_THUMBNAIL: "PHOTO_GALLERY_CLICK_THUMBNAIL",

    /**
     * Within the Photo Gallery, clicking the 'open in new tab' link
     */
    PHOTO_GALLERY_VIEW_PHOTO_NEW_TAB: "PHOTO_GALLERY_VIEW_PHOTO_NEW_TAB",

    /**
     * Within the VDP, clicking a thumbnail related to the featured photo
     */
    CLICK_FEATURED_PHOTO_THUMB: "CLICK_FEATURED_PHOTO_THUMB",

    /**
     * When clicking a link to view a vehicle's condition
     */
    CLICK_CONDITION_LINK: "CLICK_CONDITION_LINK",

    /**
     * Clicking an outbound link related to a vehicle
     */
    CLICK_OUTBOUND_LINK: "CLICK_OUTBOUND_LINK",

    /**
     * Clicking a vehicle's window sticker link
     */
    CLICK_WINDOWSTICKER_LINK: "CLICK_WINDOWSTICKER_LINK",

    /**
     * Clicking a vehicle's body link to a datasheet
     */
    CLICK_BODY_DATASHEET_LINK: "CLICK_BODY_DATASHEET_LINK",

    /**
     * Clicking a vehicle's chassis link to a datasheet
     */
    CLICK_CHASSIS_DATASHEET_LINK: "CLICK_CHASSIS_DATASHEET_LINK",

    /**
     * Clicking a vehicle's auction link
     */
    CLICK_AUCTION_LINK: "CLICK_AUCTION_LINK",

    /**
     * Clicking a VSP or VAST vehicle listing photo
     */
    CLICK_VEHICLE_LISTING_PHOTO: "CLICK_VEHICLE_LISTING_PHOTO",

    /**
     * Clicking a VSP or VAST vehicle listing title
     */
    CLICK_VEHICLE_LISTING_TITLE: "CLICK_VEHICLE_LISTING_TITLE",

    /**
     * Clicking a VSP or VAST vehicle listing "see more details" link
     */
    CLICK_VEHICLE_LISTING_SEE_DETAILS: "CLICK_VEHICLE_LISTING_SEE_DETAILS",

    /**
     * Clicking a CTA to request an upfit
     */
    CLICK_REQUEST_UPFIT: "CLICK_REQUEST_UPFIT",

    /**
     * Clicking a "more info" button related to an upfit package
     */
    CLICK_REQUEST_UPFIT_INFO: "CLICK_REQUEST_UPFIT_INFO",

    /**
     * Clicking a spec sheet related to an upfit package
     */
    CLICK_UPFIT_SPECIFICATION_SHEET: "CLICK_UPFIT_SPECIFICATION_SHEET",

     /**
     * Clicking on the view dealership website link on convoy
     */
    CLICK_VDP_COMVOY_WEBSITE_LINK: "CLICK_VDP_COMVOY_WEBSITE_LINK",

    /**
     * Choosing a vocation related to van builder or upfit requests
     */
    SELECT_UPFIT_VOCATION: "SELECT_UPFIT_VOCATION",

    /**
     * Selecting an upfit package
     */
    SELECT_UPFIT_PACKAGE: "SELECT_UPFIT_PACKAGE",

    /**
     * Exiting a request upfit form or clicking to return to other packages
     */
    CLICK_REMOVE_SELECTED_PACKAGE: "CLICK_REMOVE_SELECTED_PACKAGE",

    /**
     * Clicking to submit a Request Upfit form
     */
    SUBMIT_REQUEST_UPFIT_FORM: "SUBMIT_REQUEST_UPFIT_FORM",

    /**
     * Adding a vocation to the van builder form
     */
    SELECT_VAN_BUILDER_VOCATION: "SELECT_VAN_BUILDER_VOCATION",

    /**
     * Dealer Locator Search tracking
     */
    SELECT_DEALER_LOCATOR_SEARCH: "SELECT_DEALER_LOCATOR_SEARCH",

    /**
     * Advancing the dealer locator search page when fetching more results
     */
    SELECT_DEALER_LOCATOR_SEARCH_PAGE: "SELECT_DEALER_LOCATOR_SEARCH_PAGE",

    /**
     * Conditional search events that could occur on a dealer locator.
     */
    SELECT_DEALER_LOCATOR_SEARCH_CONDITIONAL: "SELECT_DEALER_LOCATOR_SEARCH_CONDITIONAL",

    /**
     * Checking the checkbox to show portal dealer's inventory on VAST.
     */
    CLICK_SHOW_MY_INVENTORY_ON_VAST: "CLICK_SHOW_MY_INVENTORY_ON_VAST",

    /**
     * Checking the checkbox to show sister inventory on VAST.
     */
    CLICK_SHOW_SISTER_INVENTORY_ON_VAST: "CLICK_SHOW_SISTER_INVENTORY_ON_VAST",

    /**
     * Clicking the 'AVAILABLE FOR PURCHASE' tab on VAST.
     */
    CLICK_AVAILABLE_FOR_PURCHASE_TAB_ON_VAST: "CLICK_AVAILABLE_FOR_PURCHASE_TAB_ON_VAST",

    /**
     * Clicking the 'WHOLE WTS NETWORK' tab on VAST.
     */
    CLICK_WHOLE_WTS_NETWORK_TAB_ON_VAST: "CLICK_WHOLE_WTS_NETWORK_TAB_ON_VAST",

    /**
     * Clicking the 'BRIGHTDROP POOL' tab on VAST.
     */
    CLICK_BRIGHTDROP_POOL_TAB_ON_VAST: "CLICK_BRIGHTDROP_POOL_TAB_ON_VAST",

    /**
     * Checking the checkbox to show group inventory on VAST.
     */
    CLICK_SHOW_GROUP_INVENTORY_ON_VAST: "CLICK_SHOW_GROUP_INVENTORY_ON_VAST",

   /**
     * Clicking the email of a trade contact
     */
    CLICK_EMAIL_VAST_CONTACT: "CLICK_EMAIL_VAST_CONTACT",

    /**
     * Clicking the phone number of a trade contact
     */
    CLICK_CALL_VAST_CONTACT: "CLICK_CALL_VAST_CONTACT",

    /**
     * Clicking the phone number of a dealer related to a VAST vehicle
     */
    CLICK_CALL_VAST_DEALER: "CLICK_CALL_VAST_DEALER",

    /**
     * Clicking the condition url of a VAST vehicle 
     */
    CLICK_VAST_CONDITION_LINK: "CLICK_VAST_CONDITION_LINK",

    /**
     * Clicking the auction url of a VAST vehicle
     */
    CLICK_VAST_AUCTION_LINK: "CLICK_VAST_AUCTION_LINK",

    /**
     * Clicking to submit a message to send to a VAST contact
     */
    SUBMIT_VAST_MESSAGE: "SUBMIT_VAST_MESSAGE",

    /**
     * Clicking an external link
     */
    CLICK_VAST_OUTBOUND_LINK: "CLICK_VAST_OUTBOUND_LINK",

    /**
     * Clicking to view the 'trade details' / VAST details of a VAST vehicle should trigger this
     */
    OPEN_VEHICLE_ACQUISITION_DETAILS: "OPEN_VEHICLE_ACQUISITION_DETAILS",

    /**
     * Clicking a "back to search" link or button
     */
    CLICK_BACK_TO_SEARCH_RESULTS: "CLICK_BACK_TO_SEARCH_RESULTS",

    /**
     * CLicking "Get a quote" for a Bare Chassis
     */
    CLICK_BARE_CHASSIS_INQUIRY: "CLICK_BARE_CHASSIS_INQUIRY",

    /**
     * CLicking "Get a quote" for a Body Only
     */
     CLICK_BODY_ONLY_INQUIRY: "CLICK_BODY_ONLY_INQUIRY",

    /**
     * CLicking the "Save to Garage" button
     */
    CLICK_SAVE_VEHICLE_TO_GARAGE: "CLICK_SAVE_VEHICLE_TO_GARAGE",

    /**
     * Clicking a vehicle ad from the ad loader.
     */
    CLICK_VEHICLE_AD: "CLICK_VEHICLE_AD",

    /**
     * Clicking a recently viewed vehicle from the recently viewed carousel.
     */
    CLICK_RECENTLY_VIEWED: "CLICK_RECENTLY_VIEWED",

    /**
     * Perform a conditional search for a truck.
     */
    TRUCK_SEARCH_EVENT_CONDITIONAL: "TRUCK_SEARCH_EVENT_CONDITIONAL",

    /**
     * Perform a vin search.
     */
    TRUCK_SEARCH_EVENT_VIN: "TRUCK_SEARCH_EVENT_VIN",

    TRUCK_SEARCH_EVENT_RANGE_CONDITIONAL: "TRUCK_SEARCH_EVENT_RANGE_CONDITIONAL",

    MILES_SEARCH_CONDITIONAL: "MILES_SEARCH_CONDITIONAL",

    LOCATION_SEARCH_CONDITIONAL: "LOCATION_SEARCH_CONDITIONAL",

    VOCATION_SEARCH_CONDITIONAL: "VOCATION_SEARCH_CONDITIONAL",

    TRUCK_SEARCH_CLEAR_FILTERS: "TRUCK_SEARCH_CLEAR_FILTERS",

    TRUCK_SEARCH_ZIPCODE_CHANGE: "TRUCK_SEARCH_ZIPCODE_CHANGE",

    /**
     * Searching for a truck returns no results.
     */
    TRUCK_SEARCH_EVENT_NO_RESULTS: "TRUCK_SEARCH_EVENT_NO_RESULTS",

    /**
     * Fired after a VSP search completes and the new results are rendered.
     */
    VSP_SEARCH_COMPLETE: "VSP_SEARCH_COMPLETE",

    /**
     * Clicking on truck search facets within vast.
     */
    CLICK_TRUCK_SEARCH_FACETS_VAST: "CLICK_TRUCK_SEARCH_FACETS_VAST",

    /**
     * Events that can come from the about page.
     */
    ABOUT_EVENT: "ABOUT_EVENT",

    /**
     * Clicking a custom page's email dealer button.
     */
    CLICK_CUSTOM_PAGE_EMAIL_DEAILER: "CLICK_CUSTOM_PAGE_EMAIL_DEAILER",

    TRACK_CLOSE_FORM_EVENT: "TRACK_CLOSE_FORM_EVENT",
    /**
     * Tracks various vehicle events occuring from vehicle details.
     */
    VEHICLE_DETAILS_TRACK_VEHICLE_EVENT: "VEHICLE_DETAILS_TRACK_VEHICLE_EVENT",

    /**
     * Tracks various vehicle branding events occuring from vehicle details.
     */
    VEHICLE_DETAILS_TRACK_BRANDING_EVENT: "VEHICLE_DETAILS_TRACK_BRANDING_EVENT",

    /**
     * Track when the dealer video youtube link has been clicked.
     */
    VEHICLE_DETAILS_TRACK_DEALER_VIDEO_EVENT: "VEHICLE_DETAILS_TRACK_DEALER_VIDEO_EVENT",

    /**
     * Track when the dealer video youtube link has been clicked.
     */
    VEHICLE_DETAILS_TRACK_BODY_DETAILS_VIDEO_EVENT: "VEHICLE_DETAILS_TRACK_BODY_DETAILS_VIDEO_EVENT",

    VEHICLE_DETAILS_TRACK_BODY_MANUFACTURER_VIDEO_EVENT: "VEHICLE_DETAILS_TRACK_BODY_MANUFACTURER_VIDEO_EVENT",

    VEHICLE_DETAILS_CLOSE_VIDEO_EVENT: "VEHICLE_DETAILS_CLOSE_VIDEO_EVENT",

    /**
     * Track when internal links has been clicked
     */
    VEHICLE_DETAILS_INTERNAL_LINK_CLICK: "VEHICLE_DETAILS_INTERNAL_LINK_CLICK",

    /**
     * Track when the vehicles notes read more link has been clicked
     */
    READ_MORE_VEHICLE_NOTES_CLICK: "READ_MORE_VEHICLE_NOTES_CLICK",

    /**
     * Track when the vehicles notes read less link has been clicked
     */
    READ_LESS_VEHICLE_NOTES_CLICK: "READ_LESS_VEHICLE_NOTES_CLICK",

    /**
     * Track when the vehicle options view all link has been clicked
     */
    VIEW_ALL_VEHICLE_OPTIONS_CLICK: "VIEW_ALL_VEHICLE_OPTIONS_CLICK",

    /**
     * Track when the see dealership's other listings link has been clicked
     */
    SEE_DEALERSHIPS_OTHER_LISTINGS_CLICK: "SEE_DEALERSHIPS_OTHER_LISTINGS_CLICK",


    /**
     * Tracks various garage events occurring from my garage.
     */
    MY_GARAGE_GARAGE_EVENT: "MY_GARAGE_GARAGE_EVENT",

    /**
     * Tracks various vehicle events occurring from my garage.
     */
    MY_GARAGE_VEHICLE_EVENT: "MY_GARAGE_VEHICLE_EVENT",

    /**
     * Tracks various search events occurring from inventory layout.
     */
    INVENTORY_LAYOUT_TRACK_SEARCH_EVENT: "INVENTORY_LAYOUT_TRACK_SEARCH_EVENT",

    /**
     * Tracks various locator vehicle search events from inventory layout.
     */
    INVENTORY_LAYOUT_TRACK_LOCATOR_SEARCH_EVENT: "INVENTORY_LAYOUT_TRACK_LOCATOR_SEARCH_EVENT",

    /**
     * Tracks Facetgroup events
     */
    VSP_FACETGROUP_STATE_OPEN_EVENT: "VSP_FACETGROUP_STATE_OPEN_EVENT",

    VSP_FACETGROUP_STATE_CLOSE_EVENT: "VSP_FACETGROUP_STATE_CLOSE_EVENT",

    VSP_FACETGROUP_CHASSIS_OPEN_EVENT: "VSP_FACETGROUP_CHASSIS_OPEN_EVENT",

    VSP_FACETGROUP_CHASSIS_CLOSE_EVENT: "VSP_FACETGROUP_CHASSIS_CLOSE_EVENT",

    VSP_FACETGROUP_BODY_OPEN_EVENT: "VSP_FACETGROUP_BODY_OPEN_EVENT",

    VSP_FACETGROUP_BODY_CLOSE_EVENT: "VSP_FACETGROUP_BODY_CLOSE_EVENT",

    VSP_FACETGROUP_ADDONS_OPEN_EVENT: "VSP_FACETGROUP_ADDONS_OPEN_EVENT",

    VSP_FACETGROUP_ADDONS_CLOSE_EVENT: "VSP_FACETGROUP_ADDONS_CLOSE_EVENT",

    VSP_FACETGROUP_TRAILER_OPEN_EVENT: "VSP_FACETGROUP_TRAILER_OPEN_EVENT",

    VSP_FACETGROUP_TRAILER_CLOSE_EVENT: "VSP_FACETGROUP_TRAILER_CLOSE_EVENT",

    VSP_FACETGROUP_PRICE_OPEN_EVENT: "VSP_FACETGROUP_PRICE_OPEN_EVENT",

    VSP_FACETGROUP_PRICE_CLOSE_EVENT: "VSP_FACETGROUP_PRICE_CLOSE_EVENT",

    VSP_FACETGROUP_PROGRESSIVE_OPEN_EVENT: "VSP_FACETGROUP_PROGRESSIVE_OPEN_EVENT",

    VSP_FACETGROUP_PROGRESSIVE_CLOSE_EVENT: "VSP_FACETGROUP_PROGRESSIVE_CLOSE_EVENT",

    VAST_VSP_FACETGROUP_PARTNER_OPEN_EVENT: "VAST_VSP_FACETGROUP_PARTNER_OPEN_EVENT",

    VAST_VSP_FACETGROUP_PARTNER_CLOSE_EVENT: "VAST_VSP_FACETGROUP_PARTNER_CLOSE_EVENT",

    /**
     * Tracks Facetgroup events
     */
    VSP_FACET_OPEN_EVENT: "VSP_FACET_OPEN_EVENT",

    VSP_FACET_CLOSE_EVENT: "VSP_FACET_CLOSE_EVENT",

    /*
     * Tracks changing the number of items per page on the VSP
     */
    VSP_CHANGE_ITEMS_PER_PAGE: "VSP_CHANGE_ITEMS_PER_PAGE",

    VSP_CHANGE_SORT: "VSP_CHANGE_SORT",

    /**
     * Tracks EZOrder events
     */
    EZORDER_EVENT: "EZORDER_EVENT",

    /**
     * Tracks Custom Order events
     */
    CUSTOM_ORDER_EVENT: "CUSTOM_ORDER_EVENT",

    /**
     * Tracks CV Showroom events
     */
    CVSHOWROOM_EVENT: "CVSHOWROOM_EVENT",

    /**
     * Tracks Taycor events
     */
    TAYCOR_EVENT: "TAYCOR_EVENT",

    /**
     * Tracks Crestline events
     */
    CRESTLINE_EVENT: "CRESTLINE_EVENT",

    /**
     * Tracks WebBuy events
     */
    WEBBUY_EVENT: "WEBBUY_EVENT",

    /**
     * Navigation Page Events
     */
    NAVIGATION_PAGE_PARTNER_LEARN_MORE: "NAVIGATION_PAGE_PARTNER_LEARN_MORE",
    NAVIGATION_PAGE_VIEW_ALL_PARTNERS: "NAVIGATION_PAGE_VIEW_ALL_PARTNERS",

    /**
     * Tracks Marketplace events
     */
    MARKETPLACE_EVENT: "MARKETPLACE_EVENT",

    /**
     * Custom Orders Catalog Events
     */
    COMMERCIAL_CATALOG_TOGGLE: "COMMERCIAL_CATALOG_TOGGLE",
    COMMERCIAL_CATALOG_VIEW_BODY_LINE_LITERATURE_PDF: "COMMERCIAL_CATALOG_VIEW_BODY_LINE_LITERATURE_PDF",
    COMMERCIAL_CATALOG_VIEW_BODY_LINE_VIDEO: "COMMERCIAL_CATALOG_VIEW_BODY_LINE_VIDEO",
    COMMERCIAL_CATALOG_START_REQUEST: "COMMERCIAL_CATALOG_START_REQUEST",
    COMMERCIAL_CATALOG_VIEW_PHOTO: "COMMERCIAL_CATALOG_VIEW_PHOTO",
    COMMERCIAL_CATALOG_NEXT_PHOTO: "COMMERCIAL_CATALOG_NEXT_PHOTO",
    COMMERCIAL_CATALOG_PREV_PHOTO: "COMMERCIAL_CATALOG_PREV_PHOTO",
    COMMERCIAL_CATALOG_CHANGE_BODY_TYPE: "COMMERCIAL_CATALOG_CHANGE_BODY_TYPE",
    COMMERCIAL_CATALOG_CLICK_BODY_LINE: "COMMERCIAL_CATALOG_CLICK_BODY_LINE",
    COMMERCIAL_CATALOG_CLICK_SHOW_MORE: "COMMERCIAL_CATALOG_CLICK_SHOW_MORE",
    COMMERCIAL_CATALOG_CLICK_SHOW_MORE: "COMMERCIAL_CATALOG_CLICK_SHOW_MORE",
    COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_NEXT: "COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_NEXT",
    COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_PREVIOUS: "COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_PREVIOUS",

    /**
     * Conditional Call To Action Events
     */
    CONDITIONAL_CALL_TO_ACTION: "CONDITIONAL_CALL_TO_ACTION",

    /**
    * Resource Rack Catalog Events
    */
    RESOURCE_RACK_LAUNCH_PAGE: "RESOURCE_RACK_LAUNCH_PAGE",
    RESOURCE_RACK_CHANGE_SEARCH_CONTROLS: "RESOURCE_RACK_CHANGE_SEARCH_CONTROLS",
    RESOURCE_RACK_PREVIEW_LINK_CLICK: "RESOURCE_RACK_PREVIEW_LINK_CLICK",
    RESOURCE_RACK_ACTION_MENU_GET_LINK: "RESOURCE_RACK_ACTION_MENU_GET_LINK",
    RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_COPY_LINKS: "RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_COPY_LINKS",
    RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_START_PROSPECTING: "RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_START_PROSPECTING",

    /**
    * Tracking Links History Events
    */
    TRACKING_LINKS_HISTORY_LAUNCH_PAGE: "TRACKING_LINKS_HISTORY_LAUNCH_PAGE",
    TRACKING_LINKS_HISTORY_CREATE_TRACKING_LINK: "TRACKING_LINKS_HISTORY_CREATE_TRACKING_LINK",
    TRACKING_LINKS_HISTORY_SUBMIT_TRACKING_LINK: "TRACKING_LINKS_HISTORY_SUBMIT_TRACKING_LINK",
    TRACKING_LINKS_HISTORY_CLICK_DETAILS: "TRACKING_LINKS_HISTORY_CLICK_DETAILS",
    TRACKING_LINKS_HISTORY_CLICK_EDIT_TRACKING_LINK: "TRACKING_LINKS_HISTORY_CLICK_EDIT_TRACKING_LINK",
    TRACKING_LINKS_HISTORY_CLICK_SAVE_EDIT: "TRACKING_LINKS_HISTORY_CLICK_SAVE_EDIT",
    TRACKING_LINKS_HISTORY_CLICK_DISABLE_LINK: "TRACKING_LINKS_HISTORY_CLICK_DISABLE_LINK",
    TRACKING_LINKS_HISTORY_CLICK_COPY_LINK: "TRACKING_LINKS_HISTORY_CLICK_COPY_LINK",

    /**
    * Tracking Links Email
    */
    TRACKING_LINKS_EMAIL_CLICK_SEE_LINKS: "TRACKING_LINKS_EMAIL_CLICK_SEE_LINKS",

    /**
    * Invoice Binder
    */
    INVOICE_BINDER_LAUNCH_PAGE: "INVOICE_BINDER_LAUNCH_PAGE",
    INVOICE_BINDER_SEARCH: "INVOICE_BINDER_SEARCH",
    INVOICE_BINDER_CLICK_ON_COUNT: "INVOICE_BINDER_CLICK_ON_COUNT",
    INVOICE_BINDER_CLICK_VIEW_LISTING_DETAILS: "INVOICE_BINDER_CLICK_VIEW_LISTING_DETAILS",
    INVOICE_BINDER_CLICK_MARK_IF_NOT_UPFIT: "INVOICE_BINDER_CLICK_MARK_IF_NOT_UPFIT",
    INVOICE_BINDER_CLICK_WINDOW_STICKER: "INVOICE_BINDER_CLICK_WINDOW_STICKER",
    INVOICE_BINDER_CLICK_INVOICE_LINK: "INVOICE_BINDER_CLICK_INVOICE_LINK",
    INVOICE_BINDER_CLICK_UPLOAD_INVOICES: "INVOICE_BINDER_CLICK_UPLOAD_INVOICES",
    INVOICE_BINDER_CLICK_DELETE_INVOICE: "INVOICE_BINDER_CLICK_DELETE_INVOICE",

    /**
    * PDF viewer
    */
    PDF_VIEWER_INTERNAL_LOADING: "PDF_VIEWER_INTERNAL_LOADING",
    PDF_VIEWER_CLICK_GET_SHAREABLE_LINK: "PDF_VIEWER_CLICK_GET_SHAREABLE_LINK",
    PDF_VIEWER_CLICK_GET_TRACKING_LINK: "PDF_VIEWER_CLICK_GET_TRACKING_LINK",


    /**
    * PRINTING
    */
    PRINTING_ACTION_PRINT_COMPLETE_LISTING: "PRINTING_ACTION_PRINT_COMPLETE_LISTING",
    PRINTING_ACTION_PRINT_UPFIT_WINDOW_STICKER: "PRINTING_ACTION_PRINT_UPFIT_WINDOW_STICKER",

    /**
     * Inventory Management
     */
    // General
    INVENTORY_MANAGEMENT_GROUP_SELECT_MEMBER_DEALER: 'INVENTORY_MANAGEMENT_GROUP_SELECT_MEMBER_DEALER',
    INVENTORY_MANAGEMENT_EXPORT_LISTINGS: 'INVENTORY_MANAGEMENT_EXPORT_LISTINGS',
    // Create Listing
    INVENTORY_MANAGEMENT_CREATE_BODY_ONLY_LISTING: "INVENTORY_MANAGEMENT_CREATE_BODY_ONLY_LISTING",
    INVENTORY_MANAGEMENT_CREATE_TRAILER_LISTING: "INVENTORY_MANAGEMENT_CREATE_TRAILER_LISTING",
    INVENTORY_MANAGEMENT_CREATE_VEHICLE_LISTING: "INVENTORY_MANAGEMENT_CREATE_VEHICLE_LISTING",
    // Inventory Summary
    INVENTORY_MANAGEMENT_CLICK_TOTAL_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_TOTAL_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_ON_SALE_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_ON_SALE_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_FEATURED_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_FEATURED_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_HIDDEN_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_HIDDEN_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_PRIVATE_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_PRIVATE_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_VAST_ONLY_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_VAST_ONLY_LISTINGS",
    INVENTORY_MANAGEMENT_CLICK_UNKNOWN_IF_UPFIT: "INVENTORY_MANAGEMENT_CLICK_UNKNOWN_IF_UPFIT",
    INVENTORY_MANAGEMENT_CLICK_MISSING_PHOTOS: "INVENTORY_MANAGEMENT_CLICK_MISSING_PHOTOS",
    INVENTORY_MANAGEMENT_CLICK_INVALID_PHOTOS: "INVENTORY_MANAGEMENT_CLICK_INVALID_PHOTOS",
    INVENTORY_MANAGEMENT_CLICK_NO_INVOICES: "INVENTORY_MANAGEMENT_CLICK_NO_INVOICES",
    INVENTORY_MANAGEMENT_CLICK_MANUAL_LISTINGS: "INVENTORY_MANAGEMENT_CLICK_MANUAL_LISTINGS",
    // Inventory Search
    INVENTORY_MANAGEMENT_TOGGLE_ADVANCED_SEARCH: "INVENTORY_MANAGEMENT_TOGGLE_ADVANCED_SEARCH",
    INVENTORY_MANAGEMENT_RUN_LAST_QUERY: 'INVENTORY_MANAGEMENT_RUN_LAST_QUERY',
    INVENTORY_MANAGEMENT_TEXT_SEARCH: "INVENTORY_MANAGEMENT_TEXT_SEARCH",
    INVENTORY_MANAGEMENT_FILTER_INVENTORY_SELECT: "INVENTORY_MANAGEMENT_FILTER_INVENTORY_SELECT",
    INVENTORY_MANAGEMENT_FILTER_INVENTORY_CHECKBOX: "INVENTORY_MANAGEMENT_FILTER_INVENTORY_CHECKBOX",
    INVENTORY_MANAGEMENT_RESET_FILTERS: "INVENTORY_MANAGEMENT_RESET_FILTERS",
    // Action Menu
    INVENTORY_MANAGEMENT_CLICK_VIEW_INVOICES: "INVENTORY_MANAGEMENT_CLICK_VIEW_INVOICES",
    INVENTORY_MANAGEMENT_CLICK_EDIT_PRICING: "INVENTORY_MANAGEMENT_CLICK_EDIT_PRICING",
    INVENTORY_MANAGEMENT_CLICK_EDIT_TRADE_DETAILS: "INVENTORY_MANAGEMENT_CLICK_EDIT_TRADE_DETAILS",
    INVENTORY_MANAGEMENT_CLICK_EDIT_LISTING: "INVENTORY_MANAGEMENT_CLICK_EDIT_LISTING",
    INVENTORY_MANAGEMENT_CLICK_MARK_AS_MOVED: "INVENTORY_MANAGEMENT_CLICK_MARK_AS_MOVED",
    INVENTORY_MANAGEMENT_CLICK_DELETE_LISTING: "INVENTORY_MANAGEMENT_CLICK_DELETE_LISTING",
    // Youtube Video Player
    VIDEO_PLAYER_START: "VIDEO_PLAYER_START",
    VIDEO_PLAYER_RESUME: "VIDEO_PLAYER_RESUME",
    VIDEO_PLAYER_PAUSE: "VIDEO_PLAYER_PAUSE",
    VIDEO_PLAYER_THRESHOLD: "VIDEO_PLAYER_THRESHOLD"
};;
(function (wts, modules) {

    var EventEmitter = modules.EventEmitter;

    function Visor() {
        EventEmitter.call(this);
    }

    Visor.prototype = Object.assign(EventEmitter.prototype, {

        /**
         * @static
         */
        Events: wts.UI_EVENTS,

        /**
         * @alias trigger
         * @returns {any[]} The results of the listeners
         */
        fire: function () {
            return this.trigger.apply(this, arguments);
        },

        /**
         * Fires an event and allows you to wait until all listeners to that event are done
         * @async
         * @param {string} type The event name
         * @param {any} data Event Data to be passed to listeners of this event
         * @returns {Promise} A promise that resolves with all listener promises
         */
        fireAndWait: function (type, data) {

            // filter out any listeners that are not a Thenable
            var promises = this.trigger(type, data)
                .filter(function (result) {
                    var hasResult = result !== null && typeof result !== "undefined";
                    var isThenable = false;
                    if (hasResult) {
                        isThenable = typeof result.promise !== "undefined";
                    }
                    return hasResult && isThenable;
                });

            return $.when.apply(null, promises);
        }

    });

    // export as singleton
    wts.visor = new Visor();

})(window.wts, window.wts.modules);;
(function (wts, modules) {
    /**
    * The location of any global visor event bindings
    * The UI should hook into visor here.
    *
    */

    var UI_EVENTS = wts.visor.Events;

    UI_EVENTS;

    wts.ready.then(function () {

        // phone links within ajax-updated truck search list items              
        var selector = ".truck__phone-number .truck__phone-link";
        rebindClickToCallEvent(selector);

        wts.ready.then(function (wts, modules) {
            if (wts.truckSearch) {

                wts.truckSearch.on("rebind", function () {
                    rebindClickToCallEvent(selector);
                });
            }
        });

        // phone links within the vdp pricing column
        $(".mobile-call-action-link .action-link, .advanced-pricing-actions__phone-link, .vehicle-details__comvoy-mobile-action-link-phone").click(function (e) {
            if (!wts.user.isTruckProOrAbove && window.analyticsEnabled) {

                var invID = wts.sender.getInventory().current;

                // fire and wait call us now event
                wts.visor.fireAndWait(UI_EVENTS.CALL_US_NOW_IM_INTERESTED, { inventoryID: invID });
            }
        });
    });

    /**
     * Rebinds our truck search listing `Phone Call` link event listeners.
     * @param {string} selector the class name or id of the click-to-call HTMLElement.
     * @returns {void}
     */
    function rebindClickToCallEvent(selector) {
        $(selector).off("click").click(function (e) {
            var invID = $(this).closest(".truck-listings__item").attr("data-truck-id");
            // fire and wait call us now event
            // trackClickToCallEvent("Search", "Phone Call", invID);
            wts.visor.fireAndWait(UI_EVENTS.CALL_US_NOW_IM_INTERESTED,
                {
                    category: "Search",
                    action: "Phone Call",
                    inventoryID: invID
                }
            );
        });
    }

})(window.wts, window.wts.modules);
;
(function (wts, modules) {

    // imports
    getClientData = modules.getClientData;

    // initialization of module
    var ascTrackingSetup = getClientData("#asc-tracking-setup");

    // "private static" members
    var _vocationalCarouselCurrentPage = 0;
    var _formInteractions = new Map();
    var _enableAscTracking = ascTrackingSetup.enableAscTracking;
    var _ascMeasurementIDs = ascTrackingSetup.ascMeasurementIDs;
    var _enableDebug = ascTrackingSetup.enableDebug;
    let _isResizing = false;
    let _resizeTimer;

    // Set up resize event listeners to manage the _isResizing flag
    window.addEventListener('resize', function () {
        _isResizing = true;
        clearTimeout(_resizeTimer);
        _resizeTimer = setTimeout(function () {
            _isResizing = false;
        }, 250); // 250ms delay to ensure resize event has settled
    });

    const EVENT = Object.fromEntries([
        "asc_pageview",
        "asc_item_pageview",
        "asc_itemlist_pageview",
        "asc_retail_process",
        "asc_cta_interaction",
        "asc_element_configuration",
        "asc_menu_interaction",
        "asc_media_interaction",
        "asc_special_offer",
        "asc_click_to_call",
        "asc_form_engagement",
        "asc_form_submission"
    ].map(value => [value.toUpperCase(), value]));

    const COMM_OUTCOME = Object.fromEntries([
        "appt_booked",
        "vehicle_ordered",
        "parts_ordered",
        "get_back_commitment",
        "not_opportunity",
        "robocall",
        "opportunity",
        "unknown"
    ].map(value => [value.toUpperCase(), value]));

    const COMM_STATUS = Object.fromEntries([
        "start",
        "close",
        "engage",
        "inject",
        "send_deal",
        "send_payment",
        "send_appt",
        "idle",
        "timeout",
        "unanswered",
        "transfer_abandon",
        "hold_time_abandon",
        "voicemail",
        "answered",
        "crm_update",
        "appt_booked",
        "phone_tree_keypress",
        "send",
        "agent_escalation",
        "digital_retailing_handoff",
        "load",
        "video_start",
        "video_end",
        "connect",
        "ring"
    ].map(value => [value.toUpperCase(), value]));

    const COMM_TYPE = Object.fromEntries([
        "chat",
        "sms",
        "voice",
        "video",
        "form",
        "email"
    ].map(value => [value.toUpperCase(), value]));
    
    const DEPARTMENT = Object.fromEntries([
        "sales",
        "service",
        "parts",
        "trade",
        "credit",
        "body_shop",
        "admin",
        "accessories",
        "hr",
        "custom_shop",
        "rentals",
        "unknown",
        "quick_lube"
    ].map(value => [value.toUpperCase(), value]));

    const ELEMENT_POSITION = Object.fromEntries([
        "top_left",
        "top_right",
        "top_center",
        "center_left",
        "center_right",
        "center_center",
        "bottom_left",
        "bottom_right",
        "bottom_center",
        "floating",
        "inline",
        "unknown"
    ].map(value => [value.toUpperCase(), value]));

    const ELEMENT_STATE = Object.fromEntries(
        ["active", "inactive"].map(value => [value.toUpperCase(), value])
    );

    const ELEMENT_TYPE = Object.fromEntries([
        "header",
        "banner",
        "popup",
        "form",
        "digital_retailing_tool",
        "trade_tool",
        "chat_tool",
        "accessability_tool",
        "search_tool",
        "scheduling_tool",
        "gallery",
        "map",
        "footer",
        "video",
        "item_details",
        "pagination",
        "body",
        "menu"
    ].map(value => [value.toUpperCase(), value]));

    const ELEMENT_SUBTYPE = Object.fromEntries([
        "cta_button",
        "cta_icon",
        "nav_button",
        "nav_icon",
        "nav_tab",
        "hamburger_menu",
        "mega_menu",
        "sidebar_menu",
        "inline_menu",
        "hyperlink",
        "content",
        "share_icon",
        "image",
        "input_field",
        "toggle",
        "dropdown",
        "kebab_menu",
        "hero_image"
    ].map(value => [value.toUpperCase(), value]));

    const EVENT_ACTION = Object.fromEntries([
        "click",
        "swipe_left",
        "swipe_right",
        "swipe_up",
        "swipe_down",
        "hover",
        "view",
        "scroll",
        "field_input",
        "keystroke"
    ].map(value => [value.toUpperCase(), value]));

    const EVENT_ACTION_RESULT = Object.fromEntries([
        "play",
        "restart",
        "vr_play",
        "spin",
        "popup",
        "slideout",
        "exit",
        "error",
        "search",
        "calc",
        "start",
        "stop",
        "redirect",
        "open",
        "close",
        "increase",
        "decrease",
        "clear",
        "check",
        "uncheck",
        "complete",
        "dropdown",
        "none",
        "shown",
        "next_step"
    ].map(value => [value.toUpperCase(), value]));

    const FORM_TYPE = Object.fromEntries([
        "consumer_contact",
        "trade",
        "recall",
        "parts",
        "accessories",
        "service_appointment",
        "pre-order",
        "custom",
        "bodyshop",
        "finance/credit",
        "human_resources",
        "research",
        "surveys",
        "unknown",
        "alert",
        "offer",
        "quote",
        "download",
        "shipment",
        "purchase"
    ].map(value => [value.toUpperCase(), value]));

    const MEDIA_TYPE = Object.fromEntries([
        "video",
        "image",
        "vr",
        "slider",
        "gallery",
        "offer",
        "360_platform",
        "map",
        "thumbnail"
    ].map(value => [value.toUpperCase(), value]));

    const PAGE_TYPE = Object.fromEntries([
        "item",
        "itemlist",
        "contact",
        "directions",
        "service",
        "parts",
        "accessories",
        "body_shop",
        "home",
        "build_to_order",
        "custom_page",
        "complaint",
        "employment",
        "recall",
        "finance",
        "credit",
        "trade",
        "commercial",
        "showroom",
        "unknown",
        "thank_you",
        "specials",
        "custom_orders"
    ].map(value => [value.toUpperCase(), value]));

    const ASC_MAPPINGS = {
        EVENT,
        COMM_OUTCOME,
        COMM_STATUS,
        COMM_TYPE,
        DEPARTMENT,
        ELEMENT_POSITION,
        ELEMENT_STATE,
        ELEMENT_TYPE,
        ELEMENT_SUBTYPE,
        EVENT_ACTION,
        EVENT_ACTION_RESULT,
        FORM_TYPE,
        MEDIA_TYPE,
        PAGE_TYPE
    }

    const REQUIRED_PARAMS = {
        asc_pageview: ["event_owner", "page_type", "error_code"],
        asc_retail_process: ["event_owner", "page_type", "flow_name", "element_title", "flow_outcome"],
        asc_cta_interaction: ["event_owner", "page_type", "element_text", "element_type", "element_subtype", "event_action", "event_action_result", "link_url"],
        asc_element_configuration: ["event_owner", "page_type", "event_action_result", "event_action", "element_state", "element_type", "element_subtype", "element_title", "element_text", "element_value"],
        asc_menu_interaction: ["event_owner", "page_type", "element_text", "element_subtype", "element_type", "event_action"],
        asc_media_interaction: ["event_owner", "page_type", "event_action", "event_action_result", "media_type", "link_url"],
        asc_special_offer: ["event_owner", "page_type", "promotion_name"],
        asc_click_to_call: ["event_owner", "page_type", "comm_phone_number", "department"],
        asc_form_engagement: ["event_owner", "page_type", "comm_type", "comm_status", "element_text", "department", "form_name", "form_type"],
        asc_form_submission: ["event_owner", "page_type", "comm_type", "comm_outcome", "submission_id", "element_text", "department", "form_name", "form_type"]
    }

    const OPTIONAL_PARAMS = {
        asc_pageview: ["product_name", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_results", "item_location"],
        asc_retail_process: ["flow_stage", "product_name", "item_payment", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"],
        asc_cta_interaction: ["element_color", "element_order", "product_name", "affiliation", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"],
        asc_element_configuration: ["product_name", "element_color", "element_position", "element_order"],
        asc_menu_interaction: ["product_name"],
        asc_media_interaction: ["affiliation", "creative_name", "product_name", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"],
        asc_special_offer: ["department", "product_name", "element_position", "flow_outcome"],
        asc_click_to_call: ["affiliation", "product_name", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"],
        asc_form_engagement: ["product_name", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"],
        asc_form_submission: ["product_name", "item_id", "item_number", "item_price", "item_condition", "item_year", "item_make", "item_model", "item_variant", "item_color", "item_type", "item_category", "item_inventory_date", "item_location"]
    }

    // "public" functions
    AscTracking = {
        /**
         * Resets window.asc_datalayer.items to an empty array.
         */
        resetItems: function () {
            if (!_enableAscTracking) {
                return;
            }

            window.asc_datalayer.items = [];
        },

        /**
         * Adds the specified vehicle information to the window.asc_datalayer.items array.
         * @param {any} color The color of the vehicle.
         * @param {any} condition The condition of the vehicle.
         * @param {any} fuelType The fuel type of the vehicle.
         * @param {any} vin The vin of the vehicle.
         * @param {any} createdDate The date the vehicle was added to inventory.
         * @param {any} make The make of the vehicle.
         * @param {any} model The model of the vehicle.
         * @param {any} stockNumber The stock number of the vehicle.
         * @param {any} bodyStyle The body style of the vehicle.
         * @param {any} trim The trim of the vehicle.
         * @param {any} year The year of the vehicle.
         * @param {any} price The price of the vehicle.
         * @param {any} inventoryID The Inventory ID of the vehicle.
         */
        addVehicleToAscDatalayerItems: function (color, condition, fuelType, vin, createdDate, make, model, stockNumber, bodyStyle, trim, year, price, inventoryID, location) {
            if (!_enableAscTracking) {
                return;
            }

            window.asc_datalayer.items.push({
                item_category: "",  // TODO: implement category - doc has "domestic" so we need a way of telling either foreign or domestic, example given shows the empty string
                item_color: color,
                item_condition: condition,
                item_fuel_type: fuelType,
                item_id: vin,
                item_inventory_date: createdDate,
                item_make: make,
                item_model: model,
                item_number: stockNumber,
                item_payment: "finance",  // TODO: implement other options - doc states "Payment shown, or selected which is associated with the event", example given shows "finance"
                item_type: bodyStyle,
                item_variant: trim,
                item_year: year,
                item_price: price,
                item_inventory_id: inventoryID,
                item_location: location
            });
        },

        /**
         * Tracks a page view event.
         * @param {any} event Event data giving context to the page view event.
         */
        trackPageViewEvent: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            var ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                error_code: window.asc_datalayer.error_code,
                // Optional
                item_results: Number($(".pagination__counts em:nth-child(3)").first().text()) || 1,
                ...formatData(window.asc_datalayer.items)
            };

            trackAscEvent(ascEventData);
        },

        /**
         * Tracks a general layout interaction click event that occurs when various controls from the general layout of the UI are clicked.
         * @param {any} event Event data giving context to the general layout click event.
         */
        trackGeneralLayoutInteractionClick: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            // helper function used to find the matching item in window.asc_datalayer.items
            const getMatchingItem = function ($el) {
                const truckIDTarget = $el.data('truckId') || modules.utilities.getTruckID($el);
                const marketingData = truckIDTarget
                    ? modules.getClientData(`#analytics-marketing-data-${truckIDTarget}`)  // get data from the specific #analytics-marketing-data- section (VSP or I'm Interested Form)
                    : modules.getClientData(`#marketing-events-data`);                     // get data from the #marketing-events-data section (VDP)
                return marketingData
                    ? [window.asc_datalayer.items.find(i => i.item_id === marketingData.vin)]
                    : [];
            };

            const currentTarget = event.detail;
            const $element = $(currentTarget);
            const elementText = modules.utilities.getInnerText($element);

            var ascEventData = {
                // Required for CTA events
                event: event.type,
                page_type: window.asc_datalayer.page_type,
                event_owner: window.asc_datalayer.affiliation,
                element_text: elementText,
                element_title: $element.data('asc-element-title') || "",
                element_type: event?.detail.elementType || ELEMENT_TYPE.ITEM_DETAILS,
                element_subtype: event?.detail.elementSubtype || ELEMENT_SUBTYPE.NAV_BUTTON,
                event_action: event?.detail.eventAction || EVENT_ACTION.CLICK,
                event_action_result: event?.detail.eventActionResult || EVENT_ACTION_RESULT.OPEN,
                link_url: event?.detail.linkUrl,
                // Optional
                items: window.asc_datalayer.items
            };


            if (currentTarget.href) {
                // handle all links: i.e. link back to dealer site, links to the VDP, or links in the footer

                // test to see if this is a navigation link which is different than the links within the inventory grid
                var parentElement = null;
                var testElement = $element.parent();
                const elementOptions = ["navigation__link", "mobile-auth-link", "return-home-link", "breadcrumb", "footer-nav"];

                for (option of elementOptions) {
                    if (testElement.hasClass(option)) {
                        parentElement = testElement;
                        break;
                    }
                }

                if (!parentElement) {
                    if ($element.parents(".footer-nav").length) {
                        parentElement = $element.parents(".footer-nav").first();
                    }
                }
             
                if (parentElement && parentElement.attr('class')) {
                    // header/footer link
                    ascEventData.element_type = parentElement.hasClass("footer-nav")
                        ? "footer"
                        : "header";
                    ascEventData.element_text = modules.utilities.getInnerText($element) || $element[0].innerText;

                    // Set element_title to parent dropdown text in header dropdown menus
                    if (ascEventData.element_type === "header") {
                        const dropdownLinkText = $element.closest('.dropdown').find('.dropdown__link').text().trim() || '';
                        ascEventData.element_title = dropdownLinkText;
                    }

                    // Truck Pro Login button
                    if (ascEventData.element_text === "") {
                        if ($element.hasClass("auth--login")) {
                            ascEventData.element_text = modules.utilities.getInnerText($element.children(".log-in-out-text").first());
                        }
                    }

                    // Custom orders page type
                    if (ascEventData.element_text.toLowerCase() === "custom orders") {
                        ascEventData.page_type = PAGE_TYPE.CUSTOM;
                    }

                    ascEventData.event = EVENT.ASC_MENU_INTERACTION;
                } else if ($element.hasClass("specifications__see-more")) {
                    // handles see more details link click to open the VDP from VSP
                    ascEventData.items = getMatchingItem($element);
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.is(".js-custom-orders__asc-event")) {
                    // handles see more body type details link on Custom Orders
                    ascEventData.element_text = $element[0].innerText || ascEventData.element_title;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.hasClass("truck-image")) {
                    // handles truck image click to open the VDP from VSP
                    ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                    ascEventData.media_type = MEDIA_TYPE.IMAGE;
                    ascEventData.link_url = $element.find(".truck-image__image").attr("src");
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("truck__link-text")) {
                    // handles truck title click to open the VDP from VSP
                    ascEventData.items = getMatchingItem($element);
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.hasClass("truck__phone-link")) {
                    // handles phone number click within the inventory grid item
                    ascEventData.event = EVENT.ASC_CLICK_TO_CALL;
                    ascEventData.comm_phone_number = modules.utilities.getInnerText($element);
                    ascEventData.department = DEPARTMENT.SALES;
                    ascEventData.affiliation = window.asc_datalayer.affiliation;
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("call-us-now-phone")) {
                    // handles phone number click at bottom of I'm Interested form
                    ascEventData.event = EVENT.ASC_CLICK_TO_CALL;
                    ascEventData.comm_phone_number = modules.utilities.getInnerText($element);
                    ascEventData.department = DEPARTMENT.SALES;
                    ascEventData.affiliation = window.asc_datalayer.affiliation;
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("advanced-pricing-actions__phone-link")) {
                    // handles phone number click directly on VDP
                    ascEventData.event = EVENT.ASC_CLICK_TO_CALL;
                    ascEventData.event_action = EVENT_ACTION.CLICK;
                    ascEventData.comm_phone_number = modules.utilities.getInnerText($element);
                    ascEventData.department = DEPARTMENT.SALES;
                    ascEventData.affiliation = window.asc_datalayer.affiliation;
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("photo-gallery__open-image")) {
                    // handles open click from photo gallery
                    ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                    ascEventData.media_type = MEDIA_TYPE.IMAGE;
                    ascEventData.link_url = currentTarget.href;
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("wts-vehicle-carouse__lite-item-link")) {
                    // handles vehicle click from vehicle carousel: either recently viewed or similar vehicles
                    ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                    ascEventData.element_text = $element.attr("aria-label")
                    ascEventData.media_type = MEDIA_TYPE.IMAGE;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.items = getMatchingItem($element);
                } else if ($element.hasClass("phone-link")) {
                    // handles generic phone number click
                    ascEventData.event = EVENT.ASC_CLICK_TO_CALL;
                    ascEventData.comm_phone_number = modules.utilities.getInnerText($element);
                    ascEventData.department = DEPARTMENT.SALES;
                    ascEventData.affiliation = $element.parent().siblings(".crestline-logo") ? "crestline" : window.asc_datalayer.affiliation;
                } else if ($element.hasClass("return-home-link")) {
                    // handles the return home link above the nav bar
                    ascEventData.items = getMatchingItem($element);
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = $element[0].href;
                } else if ($element[0].href.endsWith("/VanBuilder")) {
                    // handles van builder click
                    ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                    ascEventData.media_type = MEDIA_TYPE.IMAGE;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.hasClass("additional-resources__dealer-video-link")) {
                    // handles VDP view dealer video click
                    ascEventData.element_text = $element[0].innerText;
                    ascEventData.element_type = ELEMENT_TYPE.VIDEO;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = "";
                } else if ($element.hasClass("resource")) {
                    // handles VDP view window sticker click
                    ascEventData.element_text = $element.children('.resource-text')[0].innerText;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.hasClass("dynamic-link")) {
                    // handles VDP dynamic link clicks 
                    ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                    ascEventData.element_text = $element[0].textContent;
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.hasClass("toggle-link")) {
                    ascEventData.element_text = $element[0].innerText;
                    ascEventData.element_type = ELEMENT_TYPE.ITEM_DETAILS;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = "";
                } else if ($element.attr("id") === "view-vehicle-options-link") {
                    ascEventData.element_text = $element[0].innerText;
                    ascEventData.element_type = ELEMENT_TYPE.ITEM_DETAILS;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = "";
                } else if ($element.parent(".social").length) {
                    // handles social link clicks in footer
                    ascEventData.element_type = ELEMENT_TYPE.FOOTER;
                    ascEventData.element_text = $element.attr("aria-label");
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.OPEN;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.hasClass("ez-order-button--trigger")) {
                    // handles EZOrder modal launch events when the trigger is an 'a' tag
                    ascEventData.element_type = ELEMENT_TYPE.POPUP;
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.OPEN;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.hasClass("back-top")) {
                    // handles back to top click
                    ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                    ascEventData.element_text = $element[0].textContent.trim();
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.hasClass("learn-more-link")) {
                    // handle Crestline button click
                    ascEventData.element_type = ELEMENT_TYPE.DIGITAL_RETAILING_TOOL;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                    ascEventData.link_url = $element[0].href;
                } else if ($element.parent(".definition-primary-nav").length) {
                    // handles definitions A-Z nav bar click
                    ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                    ascEventData.element_text = $element[0].textContent.trim();
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.parents(".footer-static-links__list").length) {
                    // handles static footer links click
                    ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                    ascEventData.element_text = $element[0].textContent.trim();
                    ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                    ascEventData.link_url = $element[0].href;
                    ascEventData.element_subtype = ELEMENT_SUBTYPE.HYPERLINK;
                } else if ($element.hasClass("share-email")) {
                    ascEventData.element_text = $element[0].textContent.trim();
                    ascEventData.element_title = $element.data("asc-element-title");
                } else {
                    // check if it is a link in a custom header (typically a "Back to somewhere.com" link)
                    let parentDiv;

                    if ($element.parents(".custom-header").length || $element.parents(".custom-secondary-header").length || $element.parents(".header-info").length) {
                        parentDiv = $element.parents(".custom-header")[0] || $element.parents(".custom-secondary-header")[0] || $element.parents(".header-info")[0];
                    }

                    if (parentDiv) {
                        ascEventData.element_type = ELEMENT_TYPE.HEADER;
                        ascEventData.element_text = modules.utilities.getInnerText($element);
                        ascEventData.event_action_result = EVENT_ACTION_RESULT.EXIT;
                        ascEventData.link_url = currentTarget.href;
                    } else {
                        // presently an unhandled event so return which means don't fire an event
                        return;
                    }
                }
            } else if ($element.hasClass("facet-range__input")) {
                var facetGroupText = ($element.parents('.facet-filters').first().children('h4')[0] || $element.parents('.facets-theme.facet-filters').children('.facet-filters__heading')[0]).innerText.trim();

                // handle facet range changes (i.e. Year, Cab to Axle, GVRW)
                ascEventData.event = EVENT.ASC_ELEMENT_CONFIGURATION;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                ascEventData.event_action = EVENT_ACTION.FIELD_INPUT
                ascEventData.element_text = $element.val();
                ascEventData.element_title = facetGroupText;
                ascEventData.element_value = ascEventData.element_text;
                ascEventData.element_state = ascEventData.element_text ? ELEMENT_STATE.ACTIVE : ELEMENT_STATE.INACTIVE;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = $element.parent('div.facet-range__control.combobox').length ? ELEMENT_SUBTYPE.DROPDOWN : ELEMENT_SUBTYPE.INPUT_FIELD;
            } else if ($element.hasClass("facet")) {
                // Find the closest parent container for the facet group.
                var $facetGroup = $element.closest('.facet-filters');

                // Within that group, find the heading element.
                // This looks for either an <h4> or an element with the .facet-filters__heading class.
                var $heading = $facetGroup.find('h4, .facet-filters__heading').first();

                // Get the group's title from the heading's data attribute.
                var facetGroupText = $heading.data('asc-element-title');

                // Get the selected filter's text.
                // It prioritizes the data attribute and falls back to the element's inner text.
                var facetText = $element.data('asc-element-title') || modules.utilities.getInnerText($element);

                var facetCount = window.getComputedStyle($element[0], ':after').getPropertyValue('content').replace(/"/g, '').replace(/:/g, '').trim();

                // if the pseudo element contains a facet count, 
                // include it in the asc_element_text value.
                if (facetCount) {
                    facetCount = facetCount.replace(/"/g, '').replace(/:/g, '').trim();
                    facetText = `${facetText} (${facetCount})`;
                }

                // handle normal facet clicks
                ascEventData.event = EVENT.ASC_ELEMENT_CONFIGURATION;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                ascEventData.element_state = $element.hasClass("active") ? ELEMENT_STATE.ACTIVE : ELEMENT_STATE.INACTIVE;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.TOGGLE;
                ascEventData.element_title = facetGroupText;
                ascEventData.element_text = facetText;
                ascEventData.element_value = modules.utilities.getInnerText($element);
            } else if ($element.hasClass("facet-filters__clear")) {
                // handle clear search filters button
                ascEventData.element_text = $element[0].innerText.trim();
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                ascEventData.link_url = null;
            } else if ($element.hasClass("facet-filters__heading")) {
                // handle facet filter expand/collapse clicks
                ascEventData.event = EVENT.ASC_ELEMENT_CONFIGURATION;
                ascEventData.event_action_result = $element.parent().hasClass("collapsed") ? EVENT_ACTION_RESULT.OPEN : EVENT_ACTION_RESULT.CLOSE;
                ascEventData.event_action = EVENT_ACTION.CLICK
                ascEventData.element_state = ELEMENT_STATE.ACTIVE;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.DROPDOWN;
                //ascEventData.element_title = modules.utilities.getInnerText($element);
                ascEventData.element_text = modules.utilities.getInnerText($element);
                ascEventData.element_value = modules.utilities.getInnerText($element);
            } else if ($element.hasClass("pagination__list-item")) {
                // handle inventory grid pagination previous/next clicks
                var description;
                const eventProperty = $element.data("event");

                if (eventProperty === "Go To Page") {
                    description = $element.data("value");
                } else {
                    description = eventProperty.indexOf("Next") > -1 ? "Next" : "Prev";
                }

                ascEventData.element_text = description;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.NAV_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
            } else if ($element.hasClass("wts-vehicle-carousel__navigation-action--left")) {
                // handle similar/recent carousel previous clicks
                const descriptionPrefix = modules.utilities.getCarouselDescription($element).replaceAll("-", "_");

                ascEventData.element_text = `${descriptionPrefix}_previous`;
                ascEventData.element_title = `${descriptionPrefix}_previous`;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.NAV_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
            } else if ($element.hasClass("wts-vehicle-carousel__navigation-action--right")) {
                // handle similar/recent carousel next clicks
                const descriptionPrefix = modules.utilities.getCarouselDescription($element).replaceAll("-", "_");

                ascEventData.element_text = `${descriptionPrefix}_next`;
                ascEventData.element_title = `${descriptionPrefix}_next`;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.NAV_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
            } else if ($element.hasClass("wts-vehicle-carouse__lite-item-link")) {
                // handle clicking a vehicle tile within the similar/recent carousels
                ascEventData.element_text = $element.find(".wts-vehicle-card__image-container").css("url");
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.IMAGE;
                ascEventData.link_url = $element.attr("href");
            } else if ($element.hasClass("truck-actions__interested")) {
                // handle I'm Interested clicks from the VSP
                ascEventData.element_type = ELEMENT_TYPE.FORM;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.element_text = modules.utilities.getInnerText($element);
                ascEventData.items = getMatchingItem($element);
            } else if ($element.hasClass("im-interested__action")) {
                // handle I'm Interested clicks from the VDP
                ascEventData.element_text = modules.utilities.getInnerText($element);
                ascEventData.element_type = ELEMENT_TYPE.POPUP;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.items = getMatchingItem($element);
            } else if ($element.hasClass("featured-photo-gallery__see-all-photos")) {
                // handle See All Photos click from the VDP
                ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                ascEventData.media_type = MEDIA_TYPE.GALLERY;
                ascEventData.items = getMatchingItem($element);
                ascEventData.affiliation = window.asc_datalayer.affiliation;
            } else if ($element.hasClass("featured-vehicles-button")) {
                // handle Featured Vehicles button click
                ascEventData.element_text = $element[0].textContent;
                ascEventData.element_type = ELEMENT_TYPE.HEADER;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SHOWN;
            } else if ($element.is(".action-link, .email-button, .call-button")) {
                // handle email or call action link above vocational carousel
                ascEventData.element_text = $element[0].textContent;
                ascEventData.element_type = ELEMENT_TYPE.HEADER;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            } else if ($element.is(".support-link")) {
                // handle support modal in page footer
                ascEventData.element_type = ELEMENT_TYPE.FOOTER;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            } else if ($element.hasClass("crestline-transportation__get-quote")) {
                // handle Crestline button click
                ascEventData.element_text = modules.utilities.getInnerText($element),
                ascEventData.element_type = ELEMENT_TYPE.DIGITAL_RETAILING_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            } else if ($element.hasClass("crestline__generate-quote")) {
                // handle Crestline button click
                ascEventData.element_text = modules.utilities.getInnerText($element),
                ascEventData.element_type = ELEMENT_TYPE.DIGITAL_RETAILING_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            } else if ($element.hasClass("tf-gridFinancingLink__button")) {
                // handle taycor financing button click
                ascEventData.element_text = modules.utilities.getInnerText($element),
                ascEventData.element_type = ELEMENT_TYPE.DIGITAL_RETAILING_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
            } else if ($element.parent('.body-type').parent('.item').length) {
                // handle Vocational Carousel wireframe click
                const parentDiv = $element.parent('.body-type').parent('.item');

                ascEventData.event = EVENT.ASC_ELEMENT_CONFIGURATION;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.SEARCH;
                ascEventData.element_state = parentDiv.hasClass("selected") ? ELEMENT_STATE.ACTIVE : ELEMENT_STATE.INACTIVE;
                ascEventData.element_type = ELEMENT_TYPE.SEARCH_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.IMAGE;
                //ascEventData.element_title = parentDiv.children("h3")[0].innerText;
                ascEventData.element_text = parentDiv.children("h3")[0].innerText;
                ascEventData.element_value = parentDiv.children("h3")[0].innerText;
            } else if ($element.hasClass("navigation-open-button")) {
                ascEventData.event = EVENT.ASC_MENU_INTERACTION;
                ascEventData.element_type = ELEMENT_TYPE.MENU;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.HAMBURGER_MENU;
                ascEventData.element_text = "Open Mobile Menu";
                ascEventData.event_action_result = EVENT_ACTION_RESULT.OPEN;
            } else if ($element.hasClass("navigation-close-button")) {
                ascEventData.event = EVENT.ASC_MENU_INTERACTION;
                ascEventData.element_type = ELEMENT_TYPE.MENU;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.HAMBURGER_MENU;
                ascEventData.element_text = "Close Mobile Menu";
                ascEventData.event_action_result = EVENT_ACTION_RESULT.CLOSE;
            } else if ($element.is(".ez-order-button--trigger")) {
                // handle EZOrder modal button clicks
                ascEventData.element_text = $element[0].textContent;
                ascEventData.element_type = ELEMENT_TYPE.POPUP;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            } else if ($element.offsetParent('wts-webbuy-buttons')) {
                ascEventData.element_text = modules.utilities.getInnerText($element),
                ascEventData.element_type = ELEMENT_TYPE.DIGITAL_RETAILING_TOOL;
                ascEventData.element_subtype = ELEMENT_SUBTYPE.CTA_BUTTON;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.POPUP;
            }  else {
                // presently an unhandled event so return which means don't fire an event
                return;
            }

            // Route to specific event if currently set to asc_cta_interaction and properties indicate a better fit
            if (ascEventData.event === EVENT.ASC_CTA_INTERACTION) {
                if (ascEventData.element_type === ELEMENT_TYPE.MENU) {
                    ascEventData.event = EVENT.ASC_MENU_INTERACTION;
                } else if (ascEventData.element_type === ELEMENT_TYPE.GALLERY || ascEventData.element_type === ELEMENT_TYPE.VIDEO || ascEventData.media_type) {
                    ascEventData.event = EVENT.ASC_MEDIA_INTERACTION;
                } else if (ascEventData.element_type === ELEMENT_TYPE.FORM) {
                    ascEventData.event = EVENT.ASC_FORM_ENGAGEMENT;
                } else if (ascEventData.element_type === ELEMENT_TYPE.CHAT_TOOL || ascEventData.comm_type) {
                    ascEventData.event = EVENT.ASC_COMM_ENGAGEMENT;
                } else if (ascEventData.element_state || ascEventData.element_type === ELEMENT_TYPE.PAGINATION || ascEventData.element_type === ELEMENT_TYPE.SEARCH_TOOL) {
                    ascEventData.event = EVENT.ASC_ELEMENT_CONFIGURATION;
                }
            }

            if ([EVENT.ASC_CTA_INTERACTION, EVENT.ASC_CLICK_TO_CALL, EVENT.ASC_MENU_INTERACTION].includes(ascEventData.event)) {
                ascEventData = { ...ascEventData, ...formatData(ascEventData.items) }
                delete ascEventData.items;
            }

            trackAscEvent(ascEventData);
        },

        /**
         * Tracks vocational carousel page change events.
         * @param {any} event Event data giving context to the vocational carousel's present state.
         */
        trackVocationalCarouselPageChange: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            // ignore carousel events triggered by window resize
            if (_isResizing) {
                return;
            }

            const pageChangeEventData = event.detail;
            const pageNumber = pageChangeEventData.page.index;
            const pageSize = pageChangeEventData.page.size;
            const pageCount = pageChangeEventData.page.count;

            // determine if the user clicked next or previous arrow
            var direction;
            if (_vocationalCarouselCurrentPage === 0) {
                if (pageNumber === pageSize) {
                    direction = "previous";
                    _vocationalCarouselCurrentPage = pageSize;
                } else {
                    direction = "next";
                    _vocationalCarouselCurrentPage = pageNumber;
                }
            } else {
                direction = _vocationalCarouselCurrentPage <= pageNumber
                    ? "next"
                    : _vocationalCarouselCurrentPage === pageCount - 1 && pageNumber === 0
                        ? "next"
                        : "previous"
                _vocationalCarouselCurrentPage = pageNumber;
            }

            var ascEventData = {
                event: event.type,
                page_type: window.asc_datalayer.page_type,
                event_owner: window.asc_datalayer.affiliation,
                element_type: ELEMENT_TYPE.SEARCH_TOOL,
                element_text: direction,
                element_title: direction,
                event_action: EVENT_ACTION.CLICK,
                event_action_result: EVENT_ACTION_RESULT.SEARCH,
                ...formatData(window.asc_datalayer.items)
            };

            trackAscEvent(ascEventData);
        },

        /**
         * Tracks pagination control change events.
         * @param {any} event Event data giving context ot the pagination control that changed.
         */
        trackPaginationControlChange: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            var $element = $(event.detail);

            var ascEventData = {
                event: event.type,
                page_type: window.asc_datalayer.page_type,
                event_owner: window.asc_datalayer.affiliation,
                event_action_result: EVENT_ACTION_RESULT.SEARCH,
                ...formatData(window.asc_datalayer.items)
            }

            // determine if the control is located in the top or bottom nav as well as which control is being interacted with
            const $parentElement = $element.parents(".pagination-top");
            const location = $parentElement.length
                ? "header"
                : "footer";

            ascEventData.element_type = location;
            ascEventData.event_action = EVENT_ACTION.CLICK;
            ascEventData.element_text = $element[0].selectedOptions[0].innerText;
            ascEventData.element_value = $element[0].selectedOptions[0].value;
            ascEventData.element_title = $element.is("select") ? $($element[0].selectedOptions[0]).data("asc-element-title") : $element.data("asc-element-title");
            ascEventData.element_position = `${location === "header" ? "top" : "bottom"}_${$element.hasClass("items-per-page__input") ? "center" : "right"}`;
            ascEventData.element_state = $element.disabled ? "inactive" : "active";
            ascEventData.element_subtype = ELEMENT_SUBTYPE.DROPDOWN;

            trackAscEvent(ascEventData);
        },

        /**
         * Sets up the _formInteractions static member with the ID of the form being edited.
         * @param {any} event Event data giving context to the element within the form that was focused.
         */
        initializeFormStart: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            const $element = $(event.detail.currentTarget);
            const parentFormID = $element.parents(".im-interested-form").attr("id");

            if (parentFormID) {
                // I'm Interested form
                const formInteraction = _formInteractions.get(parentFormID);

                if (formInteraction) {
                    // don't fire duplicate form start events
                    return;
                }

                _formInteractions.set(parentFormID, new Map());
            } else {
                // other contact forms (email, phone)
            }
        },

        /**
         * Tracks user engagement with a form - when a form's input changes.
         * @param {any} event Event data giving context to the element within the form that was changed.
         */
        trackFormEngage: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            const $element = $(event.detail.currentTarget);
            const hiddenInventoryID = $(".hidden-inventory-id").val();
            const elementIdentifier = $element.attr("name") || $element.attr("id");
            const innerElementText = $element.siblings("label").text().replace("*", "").trim();
            let elementText = innerElementText ? innerElementText : modules.utilities.getInnerText($element);
            let elementTitle = $element.data("asc-element-title");
            let foundItems = [window.asc_datalayer.items.find((i) => i.item_inventory_id === hiddenInventoryID)];

            const ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                comm_type: COMM_TYPE.FORM,
                comm_status: event.detail.commStatus || COMM_STATUS.ENGAGE,
                element_text: elementText || elementTitle || "",
                element_title: $element.data("asc-element-title"),
                department: DEPARTMENT.SALES,
                form_name: event.detail.formName || $element.parents("section").siblings(".modal-heading")[0]?.innerText.trim() || ($element.attr("id").startsWith("ez-order") ? "EZ Order" : "") || ($element.attr("id").startsWith("NoResultsForm") ? "No Results" : ""),
                form_type: FORM_TYPE.CONSUMER_CONTACT,
                // Optional
                ...formatData(foundItems)
            };

            // Customize for callback form start
            if (event.detail.formName === 'Callback Form' || event.detail.eventName === 'Request a Callback') {
                ascEventData.element_text = 'Request a Callback';
                ascEventData.element_title = $element.data("asc-element-title") || "";
                ascEventData.form_name = 'Callback Form';
                ascEventData.form_type = FORM_TYPE.CONSUMER_CONTACT;
                ascEventData.department = DEPARTMENT.SALES;
                ascEventData.comm_status = COMM_STATUS.START;  // Ensure start for callback reveal
            }
            
            const parentFormID = $element.parents(".im-interested-form").attr("id");

            if (parentFormID) {
                const formInteraction = _formInteractions.get(parentFormID);

                if (!formInteraction) {
                    return;
                }

                var elementInteraction = formInteraction.get(elementIdentifier);

                if (elementInteraction) {
                    // don't duplicate events for the same control
                    return;
                }

                formInteraction.set(elementIdentifier, 1);
            }

            trackAscEvent(ascEventData);
        },

        /**
         * Tracks a user submitting a form.
         * @param {any} event Event data giving context to the form that was submitted.
         */
        trackFormSubmission: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            let foundItems = [window.asc_datalayer.items.find((i) => i.item_inventory_id === event.detail.inventoryID)];

            const ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                comm_type: COMM_TYPE.FORM,
                comm_outcome: COMM_OUTCOME.OPPORTUNITY,
                submission_id: event.detail.uniqueID,
                element_text: event.detail.messageType,
                department: DEPARTMENT.SALES,
                form_name: event.detail.messageType,
                form_type: FORM_TYPE.CONSUMER_CONTACT,
                // Optional
                ...formatData(foundItems)
            };

            trackAscEvent(ascEventData);
        },

        trackFormClose: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            let foundItems = [window.asc_datalayer.items.find((i) => i.item_inventory_id === event.detail.inventoryID)];

            const ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                comm_type: COMM_TYPE.FORM,
                comm_status: COMM_STATUS.CLOSE,
                comm_outcome: COMM_OUTCOME.NOT_OPPORTUNITY,
                submission_id: event?.detail?.uniqueID,
                element_text: event.detail.eventName,
                department: DEPARTMENT.SALES,
                form_name: event.detail.formName,
                form_type: FORM_TYPE.CONSUMER_CONTACT,
                // Optional
                ...formatData(foundItems)
            };
            trackAscEvent(ascEventData);
        },

        /**
         * Tracks a media interaction click.
         * @param {any} event Event data giving context to the interaction click.
         */
        trackMediaInteractionClick: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            let foundItems = [window.asc_datalayer.items.find(i => i.item_inventory_id === event.detail.inventoryID)];

            const ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                event_action: event.detail.eventAction,
                event_action_result: event.detail.eventActionResult,
                media_type: event.detail.mediaType,
                link_url: event.detail.linkUrl,
                // Optional
                affilition: window.asc_datalayer.affiliation,
                ...formatData(foundItems)
            }

            //check if ad
            $element = $(event.detail.currentTarget);
            if ($element.hasClass("dealership-top-image") || $element.hasClass("dealership-ads-left-panel-image")) {
                ascEventData.media_type = MEDIA_TYPE.IMAGE;
                ascEventData.link_url = $element.children().filter('a')[0]?.href;
                ascEventData.event_action = EVENT_ACTION.CLICK;
                ascEventData.event_action_result = EVENT_ACTION_RESULT.OPEN;
            }

            trackAscEvent(ascEventData);
        },

        /**
         * Tracks a generic interaction click event.
         * @param {any} event Event data giving context to the interaction click.
         */
        trackInteractionClick: function (event) {
            if (!_enableAscTracking) {
                return;
            }

            let foundItems = event.detail.inventoryID
                ? [window.asc_datalayer.items.find(i => i.item_inventory_id === event.detail.inventoryID)]
                : window.asc_datalayer.items;


            var ascEventData = {
                // Required
                event: event.type,
                event_owner: window.asc_datalayer.affiliation,
                page_type: window.asc_datalayer.page_type,
                element_text: event.detail.elementText,
                element_title: event.detail.elementTitle,
                element_type: event.detail.elementType,
                element_subtype: event.detail.elementSubtype,
                event_action: event.detail.eventAction,
                event_action_result: event.detail.eventActionResult,
                ...formatData(foundItems)
            };

            // Route to specific event if applicable
            let eventName = ascEventData.event;
            if (ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.MENU) {
                eventName = AscTracking.ASC_MAPPINGS.EVENT.ASC_MENU_INTERACTION;
            } else if (ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY || ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.VIDEO || ascEventData.media_type) {
                eventName = AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION;
            } else if (ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.FORM) {
                eventName = AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT;
            } else if (ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.CHAT_TOOL || ascEventData.comm_type) {
                eventName = AscTracking.ASC_MAPPINGS.EVENT.ASC_COMM_ENGAGEMENT;
            } else if (ascEventData.element_state || ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.PAGINATION || ascEventData.element_type === AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.SEARCH_TOOL) {
                eventName = AscTracking.ASC_MAPPINGS.EVENT.ASC_ELEMENT_CONFIGURATION;
            }

            ascEventData.event = eventName;

            trackAscEvent(ascEventData);
        }
    };

    // "private static" functions:

    /**
     * Helper method used to actually push event data into window.dataLayer via the gtag function (see _GoogleAnalytics.cshtml).
     * @param {any} ascEventData Event data giving context to something that needs to be tracked in GA.
     */
    trackAscEvent = function (ascEventData) {
        if (!_enableAscTracking) {
            return;
        }

        if (_enableDebug) {
            validateParams(ascEventData);
        }

        window._logGA("", ascEventData.event, "", ascEventData);
        ascEventData.send_to = _ascMeasurementIDs;
        gtag('event', ascEventData.event, ascEventData);

        window.asc_datalayer.events.unshift(ascEventData);
    };

    validateParams = function (ascEventData) {
        if (!_enableAscTracking && !ascEventData) {
            return;
        }

        const requiredParams = REQUIRED_PARAMS[ascEventData.event];
        //const optionalParams = OPTIONAL_PARAMS[ascEventData.event];

        if (requiredParams?.length) {
            const missing = requiredParams.filter(
                key => ascEventData[key] === undefined || ascEventData[key] === null
            );

            console.clear();

            if (missing.length > 0) {
                console.error(`${ascEventData.event} is missing required fields: ${missing}`);
            }
        }

        const formatted = Object.fromEntries(
            Object.entries(ascEventData).map(([key, value]) => [
                key,
                (value === null || value === "" || typeof value === "undefined") && requiredParams.includes(key) ? "❌ MISSING REQUIRED" : Array.isArray(value) ? JSON.stringify(value) : value
            ])
        );

        console.table(formatted);
    };

    formatData = function (data) {
        if (!data) return;

        const rules = {
            item_category: { dedupe: true, sort: true },
            item_color: { dedupe: true, sort: true },
            item_condition: { dedupe: true, sort: true },
            item_fuel_type: { dedupe: true, sort: true },
            item_id: { dedupe: false, sort: false },
            item_inventory_date: { dedupe: true, sort: true, isDate: true, range: true },
            item_make: { dedupe: true, sort: true },
            item_model: { dedupe: true, sort: true },
            item_number: { dedupe: false, sort: false },
            item_payment: { dedupe: true, sort: true },
            item_type: { dedupe: true, sort: true },
            item_variant: { dedupe: true, sort: true },
            item_year: { dedupe: true, sort: true, range: true },
            item_price: { dedupe: true, sort: true, range: true },
            item_inventory_id: { dedupe: false, sort: false },
            item_location: { dedupe: true, sort: true, dedupeCaseInsensitive: true },
        };

        // Step 1: Collect values
        const intermediate = {};

        for (const obj of data) {
            for (const key in obj) {
                const value = obj[key];

                // Skip nulls and empty strings
                if (value === null || value === "") continue;

                const { dedupe = true, dedupeCaseInsensitive = false } = rules[key] || {};

                if (!intermediate[key]) {
                    intermediate[key] = dedupe
                        ? dedupeCaseInsensitive
                            ? { seen: new Set(), values: [] }
                            : new Set()
                        : [];
                }

                if (!dedupe) {
                    intermediate[key].push(value);
                } else if (dedupeCaseInsensitive) {
                    const lc = typeof value === "string" ? value.toLowerCase() : value;
                    if (!intermediate[key].seen.has(lc)) {
                        intermediate[key].seen.add(lc);
                        intermediate[key].values.push(value);
                    }
                } else {
                    intermediate[key].add(value);
                }
            }
        }

        // Step 2: Format output
        const condensed = {};

        for (const key in intermediate) {
            const { sort = true, isDate = false, dedupe = true, dedupeCaseInsensitive = false, range = false } = rules[key] || {};
            let values;

            if (!dedupe) {
                values = intermediate[key];
            } else if (dedupeCaseInsensitive) {
                values = intermediate[key].values;
            } else {
                values = Array.from(intermediate[key]);
            }

            if (sort) {
                values.sort((a, b) => {
                    const valA = normalizeDate(a);
                    const valB = normalizeDate(b);

                    if (isDate && isDateLike(valA) && isDateLike(valB)) {
                        return new Date(valA) - new Date(valB);
                    }

                    if (typeof valA === "number" && typeof valB === "number") {
                        return valA - valB;
                    }

                    return String(valA).localeCompare(String(valB));
                });
            }

            if (range && values.length > 1) {
                if (isDate) {
                    condensed[key] = `${formatDate(values[0])}-${formatDate(values[values.length - 1])}`;
                } else {
                    condensed[key] = `${values[0]}-${values[values.length - 1]}`;
                }
            } else {
                condensed[key] = values.join("|");
            }
        }

        return condensed;
    };

    // Helpers
    normalizeDate = function (value) {
        return typeof value === "string" ? value.replace(/\//g, "-") : value;
    };

    isDateLike = function (value) {
        return typeof value === "string" && !isNaN(Date.parse(normalizeDate(value)));
    };

    formatDate = function (value) {
        const date = new Date(normalizeDate(value));
        const yyyy = date.getFullYear();
        const mm = String(date.getMonth() + 1).padStart(2, "0"); // months are 0-based
        const dd = String(date.getDate()).padStart(2, "0");
        return `${yyyy}/${mm}/${dd}`;
    }

    // exports
    modules.AscTracking = AscTracking;
    modules.AscTracking.ASC_MAPPINGS = ASC_MAPPINGS;

})(window.wts, window.wts.modules);
;
(function (wts, modules) {

    // imports
    var getClientData = modules.getClientData;

    // initialization of the module
    var $adobeAnalyticsSetup = getClientData("#adobe-analytics-setup");

    // "private static" members
    var _vocationalCarouselCurrentPage = 0;
    var _formInteractions = new Map();
    var _isEnabled = $adobeAnalyticsSetup.isEnabled;

    // "public static" functions
    const AdobeAnalytics = {
        /**
         * Gets common data that is embedded within the page and other places for interaction clicks.  Used for Adobe Analytics.
         * @param event Contains context around the event that was fired.
         * @returns An object containing data necessary for tracking interaction clicks or null if the module is disabled.
         */
        getAdobeInteractionClickEventData: function (event) {
            if (!_isEnabled) {
                return null;
            }

            const siteDelimiter = window.location.hostname.indexOf(".");
            const site = siteDelimiter === -1
                ? window.location.hostname
                : window.location.hostname.substring(0, siteDelimiter);

            var adobeInteractionClickData = {
                interaction: {
                    site: site,
                    type: event.data.type,
                    page: event.data.pageName || `shop:${resolveStellantisPageName()}`,
                    location: event.data.location,
                    description: event.data.description
                }
            };

            if (!event.data.hideVehicle) {
                const marketingData = getClientData(`#analytics-marketing-data-${event.data.truckID}`) || getClientData("#marketing-events-data");
                if (marketingData) {
                    adobeInteractionClickData.interaction.description = event.data.description.replace("<vehicleModel>", marketingData.model);
                    adobeInteractionClickData.vehicle = {
                        make: marketingData.make,
                        model: marketingData.model,
                        year: marketingData.year,
                        trim: marketingData.trim,
                        vin: marketingData.vin
                    };

                    if (marketingData.vin) {
                        adobeInteractionClickData.vehicle.vin = marketingData.vin;
                    }
                } else if (event.data.vin) {
                    adobeInteractionClickData.vehicle = {
                        vin: event.data.vin
                    };
                }
            }

            return adobeInteractionClickData;
        },

        /**
         * Gets common data necessary for tracking adobe form start click events.
         * @param event Contains context around the event that was fired.
         * @returns An object containing data necessary for tracking form start clicks or null if the module is disabled.
         */
        getAdobeFormStartClickEventData: function (event) {
            if (!_isEnabled) {
                return null;
            }

            var adobeFormStartClickEventData = {
                form: {
                    formDescription: event.data.formDescription,
                    formType: event.data.formType,
                    displayType: event.data.displayType,
                    displayFormat: event.data.displayFormat
                }
            };

            const marketingData = getClientData(`#analytics-marketing-data-${event.data.truckID}`) || getClientData("#marketing-events-data");
            if (marketingData) {
                adobeFormStartClickEventData.vehicle = {
                    make: marketingData.make,
                    model: marketingData.model,
                    year: marketingData.year,
                    trim: marketingData.trim,
                    vin: marketingData.vin
                };
            }

            return adobeFormStartClickEventData;
        },

        /**
         * Gets common data necessary for tracking adobe form submit events.
         * @param event Contains context around the event that was fired.
         * @returns An object containing data necessary for tracking form submit clicks or null if the module is disabled.
         */
        getAdobeFormSubmitData: function (event) {
            if (!_isEnabled) {
                return null;
            }

            var adobeFormSubmitData = {
                form: {
                    formDescription: event.data.formDescription,
                    formType: event.data.formType,
                    displayType: event.data.displayType,
                    displayFormat: event.data.displayFormat,
                    hashedEmail: event.data.hashedEmail,
                    leadId: event.data.uniqueID
                }
            };

            const marketingData = getClientData(`#analytics-marketing-data-${event.data.truckID}`) || getClientData("#marketing-events-data");
            if (marketingData) {
                adobeFormSubmitData.vehicle = {
                    make: marketingData.make,
                    model: marketingData.model,
                    year: marketingData.year,
                    trim: marketingData.trim,
                    vin: marketingData.vin
                };
            }

            return adobeFormSubmitData;
        },

        /**
         * Builds an eventData object containing interaction click event data based on information from a General Layout's currentTarget.
         * @param {any} currentTarget  The General Layout target that fired the event.
         * @returns null if the event isn't handled or the module is disabled OR the built eventData object.
         */
        getAdobeEventDataFromGeneralLayoutTarget: function (currentTarget) {
            if (!_isEnabled) {
                return null;
            }

            var $element = $(currentTarget);
            var eventData = {
                truckID: null,
                type: null,
                location: null,
                description: null,
                pageName: null
            };

            if (currentTarget.href) {
                // handle all links: i.e. link back to dealer site, links to the VDP, or links in the footer
                eventData.truckID = modules.utilities.getTruckID($element);

                // test to see if this is a navigation link which is different than the links within the inventory grid
                var parentElement = $element.parents(".navigation__link");
                if (!parentElement.length) {
                    // if not check if the link was present in the footer
                    parentElement = $element.parents(".footer-nav").first();
                }

                if (parentElement && parentElement.attr('class')) {
                    // header/footer link
                    eventData.type = "nav";
                    eventData.location = parentElement.hasClass("footer-nav")
                        ? "footer"
                        : "header";
                    eventData.description = $element.text().trim().replace(/\s+/g, '-').toLowerCase();
                } else if ($element.hasClass("specifications__see-more")) {
                    // see more details link click to open the VDP from VSP
                    eventData.type = "cta";
                    eventData.location = "vehicle-details";
                    eventData.description = "see-more-details-<vehicleModel>";
                } else if ($element.hasClass("truck-image")) {
                    // truck image click to open the VDP from VSP
                    eventData.type = "cta";
                    eventData.location = "select-vehicle";
                    eventData.description = "truck-image-<vehicleModel>";
                } else if ($element.hasClass("truck__link-text")) {
                    // truck title click to open the VDP from VSP
                    eventData.type = "cta";
                    eventData.location = "vehicle-details";
                    eventData.description = "truck-title-<vehicleModel>";
                } else if ($element.hasClass("truck__phone-link")) {
                    // phone number click within the VSP inventory grid item
                    eventData.type = "cta";
                    eventData.pageName = "landing";
                    eventData.location = "select-vehicle";
                    eventData.description = "call-phone-number-<vehicleModel>";
                } else if ($element.hasClass("call-us-now-phone")) {
                    // phone number click at bottom of I'm Interested form
                    eventData.truckID = $(".hidden-inventory-id").val();
                    eventData.type = "cta";
                    eventData.pageName = "landing";
                    eventData.location = "select-vehicle";
                    eventData.description = "call-us-now-<vehicleModel>";
                } else if ($element.hasClass("advanced-pricing-actions__phone-link")) {
                    // phone number click directly on VDP
                    eventData.type = "cta";
                    eventData.location = "vehicle-container";
                    eventData.description = "call-phone-number-<vehicleModel>";
                } else if ($element.hasClass("photo-gallery__open-image")) {
                    // open in new tab click from photo gallery
                    eventData.type = "func";
                    eventData.location = "thumbnail-gallery";
                    eventData.description = "open-in-new-tab";
                } else if ($element.hasClass("wts-vehicle-carouse__lite-item-link")) {
                    eventData.type = "slider";
                    eventData.location = "carousel-page-bottom";
                    eventData.truckID = $element.data("truckId");

                    const descriptionPrefix = modules.utilities.getCarouselDescription($element);
                    eventData.description = `${descriptionPrefix}-${$element.data("slideNumber")}`;
                } else {
                    // check if it is a link in a custom header (typically a "Back to somewhere.com" link)
                    const parentDiv = $element.parents(".custom-header") || $element.parents(".custom-secondary-header");

                    if (parentDiv) {
                        eventData.type = "nav";
                        eventData.location = "topnav";
                        eventData.description = $element.text().trim().replace(/\s+/g, '-').toLowerCase();
                    } else {
                        // presently an unhandled event so return null which means don't fire an event
                        return null;
                    }
                }
            } else if ($element.hasClass("facet-range__input")) {
                // handle facet range changes (i.e. Year, Cab to Axle, GVRW)
                eventData.type = "tool";

                const $container = $element.closest(".facet-range--container");
                eventData.location = $container.data("key").trim().replace(/\s+/g, '-').toLowerCase();
                eventData.description = `${$container.find(".facet-range__input").first().val()}-${$container.find(".facet-range__input").last().val()}`;
            } else if ($element.hasClass("facet")) {
                // handle normal facet clicks
                eventData.type = "tool";

                // get the title for the facet, trim it, replace any spaces with hyphens, and lowercase that puppy
                const headingTitle = $element.closest('.facet-filters').find('.collapsible__title').html()?.trim().replace(/\s+/g, '-').toLowerCase();
                eventData.location = headingTitle;

                eventData.description = `${window.wts.modules.utilities.getInnerText($element).toLowerCase()}-${$element.hasClass("checked") ? "checked" : "unchecked"}`;
            } else if ($element.hasClass("pagination__list-item")) {
                // handle inventory grid pagination previous/next clicks
                eventData.type = "func";
                eventData.location = "bottomnav";

                var description;
                const event = $element.data("event");

                if (event === "Go To Page") {
                    description = `pagination-${$element.data("value")}`;
                } else {
                    description = event.indexOf("Next") > -1
                        ? "pagination-next"
                        : "pagination-prev";
                }

                eventData.description = description;
            } else if ($element.hasClass("wts-vehicle-carousel__navigation-action--left")) {
                // handle similar/recent carousel previous clicks
                eventData.type = "slider";
                eventData.location = "carousel-page-bottom";
                eventData.hideVehicle = true;

                const descriptionPrefix = modules.utilities.getCarouselDescription($element);
                eventData.description = `${descriptionPrefix}-previous`;
            } else if ($element.hasClass("wts-vehicle-carousel__navigation-action--right")) {
                // handle similar/recent carousel next clicks
                eventData.type = "slider";
                eventData.location = "carousel-page-bottom";
                eventData.hideVehicle = true;

                const descriptionPrefix = modules.utilities.getCarouselDescription($element);
                eventData.description = `${descriptionPrefix}-next`;
            } else if ($element.hasClass("wts-vehicle-carouse__lite-item-link")) {
                // handle clicking a vehicle tile within the similar/recent carousels
                eventData.type = "slider";
                eventData.location = "carousel-page-bottom";
                eventData.description = `${modules.utilities.getCarouselDescription($element)}-tile`;
            } else if ($element.hasClass("truck-actions__interested")) {
                // handle I'm Interested clicks from the VSP
                eventData.truckID = modules.utilities.getTruckID($element);
                eventData.type = "cta";
                eventData.pageName = "landing";
                eventData.location = "select-vehicle";
                eventData.description = "contact-your-dealer-<vehicleModel>";
            } else if ($element.hasClass("im-interested__action")) {
                // handle I'm Interested clicks from the VDP
                eventData.type = "cta";
                eventData.location = "vehicle-container";
                eventData.description = "Interested-<vehicleModel>";
            } else if ($element.hasClass("featured-photo-gallery__see-all-photos")) {
                // handle See All Photos click from the VDP
                eventData.type = "tool";
                eventData.location = "vehicle-container"
                eventData.description = "gallery-seeAllPhotos";
            } else {
                // presently an unhandled event so return null which means don't fire an event
                return null;
            }

            return { data: eventData };
        },

        /**
         * Builds an eventData object based on information from currentTarget which is a specific pagination control.
         * @param {any} currentTarget The specific pagination control that fired the event.
         * @returns An eventData object containing information derived from the pagination control that fired the event or null if the module is disabled.
         */
        getAdobeEventDataFromPaginationControls: function (currentTarget) {
            if (!_isEnabled) {
                return null;
            }

            const $element = $(currentTarget);
            var eventData = {
                type: "func",
                location: "",
                description: ""
            };

            // determine if the control is located in the top or bottom nav as well as which control is being interacted with
            const $parentElement = $element.parents(".pagination-top");
            const location = $parentElement.length
                ? "topnav"
                : "bottomnav";
            eventData.location = location;

            const selectedText = $element.find(":selected").text().replace(/\s+/g, '-').replace(/\(/g, '').replace(/\)/g, '').toLowerCase();
            eventData.description = `${$element.hasClass("items-per-page__input") ? "items-per-page" : "sort-by"}-${selectedText}`;

            return { data: eventData };
        },

        /**
         * Builds an eventData object based on information from pageChangeEventData.
         * @param {any} pageChangeEventData The specific pageChangeEventData to build the eventData from.
         * @returns An eventData object containing information derived from the pageChangeEventData or null if the module is disabled.
         */
        getAdobeEventDataFromVocationalPageChange: function (pageChangeEventData) {
            if (!_isEnabled) {
                return null;
            }

            var eventData = {
                type: "filter",
                location: "main-filter-carousel",
                description: ""
            };
            const pageNumber = pageChangeEventData.page.index;
            const pageSize = pageChangeEventData.page.size;
            const pageCount = pageChangeEventData.page.count;

            // determine if the user clicked next or previous arrow
            var direction;
            if (_vocationalCarouselCurrentPage === 0) {
                if (pageNumber === pageSize) {
                    direction = "previous";
                    _vocationalCarouselCurrentPage = pageSize;
                } else {
                    direction = "next";
                    _vocationalCarouselCurrentPage = pageNumber;
                }
            } else {
                direction = _vocationalCarouselCurrentPage <= pageNumber
                    ? "next"
                    : _vocationalCarouselCurrentPage === pageCount - 1 && pageNumber === 0
                        ? "next"
                        : "previous"
                _vocationalCarouselCurrentPage = pageNumber;
            }

            eventData.description = `filter-${pageNumber + 1}:${direction}`;
            return { data: eventData };
        },

        /**
         * Builds an eventData object based on form control information derived from currentTarget.
         * @param {any} currentTarget The specific element inside a form that fired the event.
         * @returns null if the parentFormID cannot be derived or if the form has already been interacted with or the module is disabled.
         * An eventData object containing information derived from currentTarget otherwise.
         */
        getAdobeEventDataFromFormStart: function (currentTarget) {
            if (!_isEnabled) {
                return null;
            }

            const $element = $(currentTarget);
            const parentFormID = $element.parents(".im-interested-form").attr("id");

            if (!parentFormID) {
                return null;
            }

            var formInteraction = _formInteractions.get(parentFormID);
            if (formInteraction) {
                // the user has already interacted with the form so don't fire an event
                return null;
            }

            formInteraction = new Map();
            _formInteractions.set(parentFormID, formInteraction);

            var eventData = {
                truckID: $(".hidden-inventory-id").val(),
                formDescription: "lead",
                formType: "ram-wts-form",
                displayType: "page",
                displayFormat: "in-page",
            };
            return { data: eventData };
        },

        /**
         * Gets common data that is embedded within the page and other places for page loads.  Used for Adobe Analytics.
         * @param event Contains context around the event that was fired.
         * @returns An object containing data necessary for tracking page loads or null if the module is disabled.
         */
        getAdobePageLoadEventData: function (event) {
            if (!_isEnabled) {
                return null;
            }

            const userData = getClientData("#user-data");
            const location = window.wts.user.location.get();
            const pageName = resolveStellantisPageName();
            var adobePageLoadData = {
                platform: {
                    technology: ".NET",
                },
                user: {
                    language: userData.language,
                    responsiveState: detectDeviceType(),
                    zipCode: location ? location.ZipCode : "",
                },
                page: {
                    name: `shop:${pageName}`,
                    type: pageName
                }
            };

            const marketingEventsData = getClientData("#marketing-events-data");
            if (marketingEventsData) {
                adobePageLoadData.vehicle = {
                    make: marketingEventsData.make,
                    model: marketingEventsData.model,
                    year: marketingEventsData.year,
                    trim: marketingEventsData.trim,
                    vin: marketingEventsData.vin
                };
            }

            const siteData = getClientData("#site-data");
            adobePageLoadData.dealer = {
                code: siteData.DealerCode
            };

            return adobePageLoadData;
        }
    };

    // "private static" functions

    /**
     * Detects the device type by observing different window.matchMedia queries to test the screen's width and determine
     * either Desktop, Tablet, or Mobile.
     * @returns "desktop", "tablet", or "mobile" depending on the screen width of the window.
     */
    function detectDeviceType() {
        if (window.matchMedia("(min-width: 90rem)").matches) {
            return "desktop";
        } else if (window.matchMedia("(min-width: 40rem)").matches) {
            return "tablet";
        } else {
            return "mobile";
        }
    };

    /**
     * Attempts to map the pageType from the page-context-data into a value Stellantis expects.
     * @returns the resolved pageName
     */
    function resolveStellantisPageName() {
        const pageContextData = window.wts.modules.getClientData("#page-context-data");
        if (!pageContextData) {
            return null;
        }

        switch (pageContextData.pageType) {
            case "SearchResults":
                return "search-inventory";
            case "TruckDetails":
                return "vehicle-details";
                break;
            default:
                return "not-handled";
        }
    };

    // exports
    modules.AdobeAnalytics = AdobeAnalytics;

})(window.wts, window.wts.modules);
;
(function (wts, modules) {
    /**
    * The location of our visor event listeners
    * Marketing libraries should hook into visor from here
    *
    * @example
    * wts.visor.on(UI_EVENTS.PAGE_VIEW, function(e){
    *     //...
    * });
    *
    */

    var UI_EVENTS = wts.visor.Events;
    var AscTracking = modules.AscTracking;
    var AdobeAnalytics = modules.AdobeAnalytics;
    var getClientData = modules.getClientData;

    // this script is rendered before the @data section, so we must defer
    var pageData = getClientData("#page-context-data");

    // TODO: this is used by setAnalyticsCTAEvent
    //var analyticsData = getClientData("#ga-data");
    var vehicleCategory = pageData.isVast ? "VAST" : "Vehicle";

    const trackAdobeEvent = window.TrackAdobeEvent || console.log;

    wts.visor.on(UI_EVENTS.PAGE_VIEW, function (event) {
        var MarketingEvents = modules.MarketingEvents;
        var VehicleViewData = modules.VehicleViewData;
        var data = getClientData("#marketing-events-data");

        if (event.data.context === "VDP") {

            if (data.stockType !== "Used") {
                data.stockType = "New";
            }

            var vehicleViewData = new VehicleViewData(
                data.inventoryID,
                data.dealerInventoryNumericID,
                data.zipCode,
                data.make,
                data.model,
                data.year,
                data.stockType,
                data.color,
                data.transmissionType,
                data.bodyStyle,
                data.fuelType,
                data.driveTrain,
                data.price,
                data.trim,
                data.mileage,
                data.vin,
                data.fuelType
            );

            MarketingEvents.vehicleView(vehicleViewData);
            AscTracking.trackPageViewEvent(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_ITEM_PAGEVIEW));
        } else if (event.data.context === "VAST" || event.data.context === "VSP") {
            AscTracking.trackPageViewEvent(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_ITEMLIST_PAGEVIEW));
        }

        const ascEventData = {
            pageType: event.data.context
        };

        AscTracking.trackPageViewEvent(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_PAGEVIEW, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PAGE_LOAD, function (event) {
        var adobePageData = AdobeAnalytics.getAdobePageLoadEventData(event);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("page-load", { detail: adobePageData }));
        }
    });

    wts.visor.on(UI_EVENTS.INTERACTION_CLICK, function (event) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(event);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: event.data.currentTarget.innerText.trim(),
            elementTitle: event.data.currentTarget.dataset.ascElementTitle || "",
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.ACCESSABILITY_TOOL,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.CTA_BUTTON,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.SEARCH
        };
        AscTracking.trackInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.SEE_MORE_INTERACTION_CLICK, function (event) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(event);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }
    });

    wts.visor.on(UI_EVENTS.GENERAL_LAYOUT_INTERACTION_CLICK, function (event) {
        var adobeEventData = AdobeAnalytics.getAdobeEventDataFromGeneralLayoutTarget(event.data.currentTarget);

        if (adobeEventData) {
            var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(adobeEventData);
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: event.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VOCATIONAL_CAROUSEL_PAGE_CHANGE, function (event) {
        var adobeEventData = AdobeAnalytics.getAdobeEventDataFromVocationalPageChange(event.data.pageChangeEventData);

        if (adobeEventData) {
            var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(adobeEventData);
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackVocationalCarouselPageChange(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: event.data.pageChangeEventData }));
    });

    wts.visor.on(UI_EVENTS.PAGINATION_CONTROL_CHANGE, function (event) {
        var adobeEventData = AdobeAnalytics.getAdobeEventDataFromPaginationControls(event.data.currentTarget);

        if (adobeEventData) {
            var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(adobeEventData);
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackPaginationControlChange(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_ELEMENT_CONFIGURATION, { detail: event.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_SEARCH_COMPLETE, function (e) {
        var viewModel = e.data.viewModel;

        // Fire both the itemlist and the generic pageview events, mirroring the initial page load behavior
        const ascEventData = {
            pageType: viewModel.Layout.FeatureArea
        };

        AscTracking.trackPageViewEvent(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_ITEMLIST_PAGEVIEW, { detail: ascEventData }));
        AscTracking.trackPageViewEvent(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_PAGEVIEW, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.FORM_START, function (event) {
        var adobeEventData = AdobeAnalytics.getAdobeEventDataFromFormStart(event.data.currentTarget);

        if (adobeEventData) {
            var adobePageData = AdobeAnalytics.getAdobeFormStartClickEventData(adobeEventData);
            trackAdobeEvent(new CustomEvent("form-start", { detail: adobePageData }));
        }

        AscTracking.initializeFormStart(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, { detail: { currentTarget: event.data.currentTarget } }));
    });

    wts.visor.on(UI_EVENTS.FORM_ENGAGE, function (event) {
        AscTracking.trackFormEngage(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, { detail: { currentTarget: event.data.currentTarget } }));
    });

    wts.visor.on(UI_EVENTS.CALL_US_NOW_IM_INTERESTED, function (event) {

        if (!wts.user.isTruckProOrAbove) {

            // CASE: on different pages this has different categories
            var category = "Vehicle";
            var inventoryID = event.data.inventoryID;

            if (typeof window.analyticsDimensions !== "undefined") {
                category = "Search";
            }

            getLabelAndDimensions(inventoryID, function (label, dimensions) {
                window.TrackEvent(category, "Phone Call", label, dimensions);
            });
        }
    });

    wts.visor.on(UI_EVENTS.CALLBACK_REQUEST_CLICK, function (event) {
        AscTracking.initializeFormStart(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, {
            detail: {
                currentTarget: event.data.currentTarget
            }
        }));

        // Fire the start engagement event
        AscTracking.trackFormEngage(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, {
            detail: {
                currentTarget: event.data.currentTarget,
                formName: 'Callback Form',
                eventName: 'Request a Callback',
                commStatus: 'start'
            }
        }));
    });

    wts.visor.on(UI_EVENTS.CLICK_SUPPORT_LINK, function () {
        TrackEvent("Support", "Support Link Clicked", "");
        window.lastEvent = "Support Link Clicked";
    });

    wts.visor.on(UI_EVENTS.SUBMIT_VEHICLE_INQUIRY_FORM, function (e) {
        var inventoryID = e.data;
        modules.MarketingEvents.vehicleLead(new modules.VehicleLeadData(inventoryID));

        if (inventoryID) {
            getLabelAndDimensions(inventoryID, function (label, dimensions) {
                window.TrackEvent(vehicleCategory, "New Lead", label, dimensions);
            });
        }
        else if (window.isGarage) {
            window.TrackEvent("Garage", "New Lead");
        }
        else if (window.isAbout) {
            window.TrackEvent("About", "New Lead");
        }
        else if (window.isCustomPage) {
            window.TrackEvent(window.customPageName, "New Lead");
        }
        else if (pageData.isVSP) {
            // a VSP without an inventoryID must be No Results... right?
            window.TrackEvent("Search", "New Lead");
        }

        return modules.MarketingEvents.wait();
    });

    wts.visor.on(UI_EVENTS.SUBMIT_VEHICLE_INQUIRY_FORM_ERROR, function (event) {
        trackAdobeEvent(new CustomEvent("error-display", {
            detail: {
                error: {
                    message: event.data.message,
                    type: event.data.type
                }
            }
        }));
    });

    wts.visor.on(UI_EVENTS.SUBMIT_LOAD_GARAGE_FORM, function () {
        TrackEvent("Sign Up", "New Lead");
    });

    wts.visor.on(UI_EVENTS.WAIT_FOR_FORM_CONFIRMATION, function (e) {
        var data = e.data;
        var inventoryID = data.inventoryID;

        var adobePageData = AdobeAnalytics.getAdobeFormSubmitData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("form-submit", { detail: adobePageData }));
        }
        
        AscTracking.trackFormSubmission(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_SUBMISSION, { detail: { uniqueID: data.uniqueID, inventoryID: data.inventoryID, messageType: data.messageType } }));

        if (data.isSupportRequest) {
            TrackEvent("Support", "Support Link Clicked Confirmed");
            return;
        }

        var action = (function () {

            if (data.isCallbackMessage) {
                return "Phone Dealer Confirmed";
            }
            if (data.isNoResultsMessage) {
                return "No Results Confirmed";
            }

            if (window.lastEvent === "Tell Me More" ||
                window.lastEvent === "I'm Interested" ||
                window.lastEvent === "Email Dealer" ||
                window.lastEvent === "Bare Chassis Request") {
                return window.lastEvent + " Confirmed";
            }

            return "";
        })();

        if (window.lastEvent === "Support Link Clicked" || window.lastEvent === "Support Link Clicked Confirmed") {
            TrackEvent("Support", action, "");
        }
        else if (inventoryID) {
            getLabelAndDimensions(inventoryID, function (label, dimensions) {
                window.TrackEvent(vehicleCategory, action, label, dimensions);
            });
        }
        else if (typeof window.isGarage !== "undefined") {
            // trackGarageEvent(action);
            TrackEvent("Garage", action);
        }
        else if (typeof window.isAbout !== "undefined") {
            // trackAboutEvent(action);
            TrackEvent("About", action);
        }
        else if (typeof window.isEZOrder !== "undefined") {
            // trackEZOrderEvent(action)
            TrackEvent("EZOrder", action);
        }
        else if (typeof window.isCustomOrder !== "undefined") {
            // trackCustomOrderEvent(action)
            TrackEvent("CustomOrder", action);
        }
        else if (window.isCustomPage) {
            TrackEvent(window.customPageName, action);
        }
        else if (typeof trackSearchEvent === "function") {
            // there are 2 trackSearchEvents — one for searchv1 and one for v2 (in _InventoryLayout)
            // trackSearchEvent(action);
            TrackEvent("Search", action);
        }

    });

    wts.visor.on(UI_EVENTS.OPEN_VEHICLE_INQUIRY_FORM, function (e) {
        // TIPS FOR WIZARDS:
        // When interacting with the CTA on VSP we trigger "Tell Me More"
        //                           and on VDP we trigger "I'm Interested"
        //
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            if (pageData.isVSP) {
                window.TrackEvent(vehicleCategory, "Tell Me More", label, dimensions);
            }
            else if (pageData.isVDP) {
                window.TrackEvent(vehicleCategory, "I'm Interested", label, dimensions);
            }
        });
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_INTERNAL_LINK_CLICK, function (e) {
        var inventoryID = e.data.inventoryID;
        var attributeName = e.data.attributeName;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "VDP Internal Link Click", `${attributeName} - ${label}`, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_FEATURED_PHOTO_THUMB, function (e) {
        TrackEvent(vehicleCategory, "Click Thumbnail [C]", window.myAnalyticsLabel, window.myAnalyticsDimensions);

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.OPEN,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.IMAGE,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.SUBMIT_CUSTOM_FORM, function (e) {
        var action = "Submit Form";
        var category = "Custom Form";
        var label = `${e.data.dealerName} - ${e.data.formName}`;
        TrackEvent(category, action, label);
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_OPEN, function (e) {
        var index = e.data.current;
        var isVDP = e.data.isVDP;
        var inventoryID = e.data.inventoryID;

        var isBodySide = index === 1;

        var side = isVDP ? "[D]" : "[C]";
        if (isBodySide) {
            side = isVDP ? "[DB]" : "[B]";
        }

        var action = ["View Photos ", side].join("");

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, action, label, dimensions);
        });

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.OPEN,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.IMAGE,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_CLOSE, function (e) {

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.CLOSE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_NEXT_PHOTO, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "View Next Photo", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.INCREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_PREVIOUS_PHOTO, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "View Previous Photo", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.DECREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_CLICK_THUMBNAIL, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "View Photo via Thumbnail", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.OPEN,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.IMAGE,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_NEXT_PAGE, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Page Thumbnails Next", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.INCREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_PREVIOUS_PAGE, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Page Thumbnails Previous", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.DECREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.FEATURED_PHOTO_GALLERY_NEXT_PHOTO, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "View Next Photo", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.INCREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.FEATURED_PHOTO_GALLERY_PREVIOUS_PHOTO, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "View Previous Photo", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.DECREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.FEATURED_PHOTO_GALLERY_NEXT_PAGE, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Page Thumbnails Next", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.INCREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.FEATURED_PHOTO_GALLERY_PREVIOUS_PAGE, function (e) {
        var inventoryID = e.data.inventoryID;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Page Thumbnails Previous", label, dimensions);
        });

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.DECREASE,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.PHOTO_GALLERY_VIEW_PHOTO_NEW_TAB, function (e) {
        getLabelAndDimensions(e.data.inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Open in New Tab", label, dimensions);
        });

        const ascEventData = {
            elementText: e.data.description,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.GALLERY,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.OPEN,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.HYPERLINK,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.GALLERY,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.CLICK_CONDITION_LINK, function (e) {
        TrackEvent(vehicleCategory, "View Condition", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_OUTBOUND_LINK, function (e) {
        var linkURL = e.data;
        TrackEvent(vehicleCategory, "View Outbound Link", linkURL, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_WINDOWSTICKER_LINK, function (e) {
        TrackEvent(vehicleCategory, "Window Sticker", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_BODY_DATASHEET_LINK, function (e) {
        var category = pageData.isVast ? "VAST" : "Branding";
        TrackEvent(category, "Click Datasheet", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_CHASSIS_DATASHEET_LINK, function (e) {
        var category = pageData.isVast ? "VAST" : "Branding";
        var resourceURL = e.data;
        TrackEvent(category, "Click Datasheet", resourceURL, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_TRACK_DEALER_VIDEO_EVENT, function (e) {
        var category = pageData.isVast ? "VAST" : "Vehicle";
        TrackEvent(category, "View Dealer Video", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_TRACK_BODY_DETAILS_VIDEO_EVENT, function (e) {
        var category = pageData.isVast ? "VAST" : "Vehicle";
        TrackEvent(category, "View Body Details Video", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_TRACK_BODY_MANUFACTURER_VIDEO_EVENT, function (e) {
        var category = pageData.isVast ? "VAST" : "Vehicle";
        TrackEvent(category, "View Body Manufacturer Video", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_CLOSE_VIDEO_EVENT, function (e) {
        var category = pageData.isVast ? "VAST" : "Vehicle";
        TrackEvent(category, "Close Video", window.myAnalyticsLabel, window.myAnalyticsDimensions);

        const ascEventData = {
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.VIDEO,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
            eventActionResult: AscTracking.ASC_MAPPINGS.EVENT_ACTION_RESULT.EXIT,
            inventoryID: e.data.inventoryID,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.NAV_ICON,
            linkUrl: null,
            mediaType: AscTracking.ASC_MAPPINGS.MEDIA_TYPE.VIDEO,
        };
        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.VSP_CHANGE_ITEMS_PER_PAGE, function (e) {
        var vehicleCategory = pageData.isVast ? "VAST" : "Search";
        TrackEvent(vehicleCategory, "Items Per Page", e.data.data);
    });

    wts.visor.on(UI_EVENTS.VSP_CHANGE_SORT, function (e) {
        var vehicleCategory = pageData.isVast ? "VAST" : "Search";
        TrackEvent(vehicleCategory, "Sort By", e.data.data);
    });

    wts.visor.on(UI_EVENTS.CLICK_AUCTION_LINK, function (e) {
        TrackEvent(vehicleCategory, "View Auction", window.myAnalyticsLabel, window.myAnalyticsDimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_VEHICLE_LISTING_TITLE, function (e) {
        var inventoryID = e.data;

        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            if (pageData.isVast) {
                window.TrackEvent(vehicleCategory, "View VAST VDP - Title", label, dimensions);
            }
            else {
                window.TrackEvent(vehicleCategory, "More Info - Title", label, dimensions);
            }
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_VEHICLE_LISTING_PHOTO, function (e) {
        var isChassisSide = e.data.isChassisSide;
        var inventoryID = e.data.inventoryID;
        // when clicking a link, the chassis side has [C] and the body side has [B]
        var side = isChassisSide ? "[C]" : "[B]";

        var action = "{action} - Photo {side}".replace("{side}", side);

        getLabelAndDimensions(inventoryID, function (labels, dimensions) {
            if (pageData.isVast) {
                action = action.replace("{action}", "View VAST VDP")
                window.TrackEvent(vehicleCategory, action, labels, dimensions);
            }
            else {
                action = action.replace("{action}", "More Info")
                window.TrackEvent(vehicleCategory, action, labels, dimensions);
            }
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_VEHICLE_LISTING_SEE_DETAILS, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            if (pageData.isVast) {
                window.TrackEvent(vehicleCategory, "View VAST VDP - See More Details", label, dimensions);
            }
            else {
                window.TrackEvent(vehicleCategory, "More Info - See More Details", label, dimensions);
            }
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_REQUEST_UPFIT, function (e) {
        var selectedPackage = e.data;
        var label = selectedPackage === null ? "" : selectedPackage;

        TrackEvent("RequestAnUpfit", "Request for Upfit With Truck", label);
        window.lastEvent = "Request for Upfit With Truck";
    });

    wts.visor.on(UI_EVENTS.CLICK_REQUEST_UPFIT_INFO, function (e) {
        var selectedPackage = e.data;
        var label = selectedPackage === null ? "" : selectedPackage;
        TrackEvent("LookingForAnUpfit", "View More Info", label);
    });

    wts.visor.on(UI_EVENTS.CLICK_UPFIT_SPECIFICATION_SHEET, function (e) {
        var selectedPackage = e.data;
        TrackEvent("LookingForAnUpfit", "Clicked Spec Sheet", selectedPackage);
    });

    wts.visor.on(UI_EVENTS.CLICK_VDP_COMVOY_WEBSITE_LINK, function (e) {
        var linkURL = e.data;
        TrackEvent("Vehicle", "Click Dealer Website Link", linkURL);
    });

    wts.visor.on(UI_EVENTS.SELECT_UPFIT_VOCATION, function (e) {
        var vocation = e.data;
        TrackEvent("LookingForAnUpfit", "Chose a Vocation", vocation);
    });

    wts.visor.on(UI_EVENTS.CLICK_REMOVE_SELECTED_PACKAGE, function (e) {
        TrackEvent("LookingForAnUpfit", "Browse Other Upfits");
    });

    wts.visor.on(UI_EVENTS.SELECT_UPFIT_PACKAGE, function (e) {
        var selectedPackage = e.data;
        TrackEvent("LookingForAnUpfit", "Select Package", selectedPackage);
    });

    wts.visor.on(UI_EVENTS.SUBMIT_REQUEST_UPFIT_FORM, function (e) {
        var selectedPackage = e.data;
        window.TrackEvent("RequestAnUpfit", undefined, selectedPackage);
    });

    wts.visor.on(UI_EVENTS.SELECT_VAN_BUILDER_VOCATION, function (e) {
        var vocation = e.data;
        window.TrackEvent("VanBuilder", "Chose a Vocation", vocation);
    });

    wts.visor.on(UI_EVENTS.ABOUT_EVENT, function (e) {
        var eventName = e.data.eventName;
        var value = e.data.value;

        window.TrackEvent("About", eventName, value);
        var currentTarget = e.data.value.currentTarget;

        if (currentTarget) {
            AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: currentTarget }));
        }
    });

    wts.visor.on(UI_EVENTS.EZORDER_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);

        ascEventData = {
            commType: AscTracking.ASC_MAPPINGS.COMM_TYPE.FORM,
            commStatus: action.startsWith("Open") ? AscTracking.ASC_MAPPINGS.COMM_STATUS.START : action.startsWith("Close") ? AscTracking.ASC_MAPPINGS.COMM_STATUS.CLOSE : AscTracking.ASC_MAPPINGS.COMM_STATUS_ENGAGE,
            formName: "EZ Order",
            currentTarget: e.data.currentTarget
        };

        AscTracking.trackFormEngage(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.CUSTOM_ORDER_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);
    });

    wts.visor.on(UI_EVENTS.TAYCOR_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);
    });

    wts.visor.on(UI_EVENTS.CRESTLINE_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.WEBBUY_EVENT, function (e) {
        var category = pageData.isVSP ? "Search" : "Vehicle";
        var action = null;
        var label = null;

        if (e.data) {
            var el = e.data;

            let title = el.getAttribute("vehicleTitle");
            let vin = el.getAttribute("vin");

            label = title && vin ? title + " - " + vin : label;

            switch (el.innerHTML.toLowerCase()) {
                case "buy now":
                    action = "Click WebBuy Buy Now CTA";
                    break;
                case "instant trade offer":
                    action = "Click WebBuy Instant Trade Offer CTA";
                    break;
                case "get financed online":
                    action = "Click WebBuy Get Financed Online CTA";
                    break;
                default:
                    // no-op
                    break;
            }

            if (action && label) {
                window.TrackEvent(category, action, label);
            }

            AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data }));
        }

        
    });

    wts.visor.on(UI_EVENTS.CVSHOWROOM_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);
    });

    wts.visor.on(UI_EVENTS.CLICK_CUSTOM_PAGE_EMAIL_DEAILER, function (e) {
        var customPageName = e.data.customPageName;
        TrackEvent(customPageName, "Email Dealer");
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_TRACK_VEHICLE_EVENT, function (e) {
        var eventName = e.data.eventName;
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        TrackEvent("Vehicle", eventName, label, dimensions);

        e.data.type = "cta";
        e.data.page = "shop-vehicle-detais";
        e.data.location = "vehicle-container";

        if (eventName === "Print Confirmed") {
            e.data.description = "gallery-print";
        } else if (eventName.indexOf("Share - ") > -1) {
            e.data.description = "social-share";
        } else {
            // if eventName isn't explicitly handled then dont track the adobe event
            return;
        }

        const adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        const ascEventData = {
            elementText: e.data.eventName,
            elementTitle: e.data.elementTitle,
            elementSubtype: AscTracking.ASC_MAPPINGS.ELEMENT_SUBTYPE.HYPERLINK,
            elementType: AscTracking.ASC_MAPPINGS.ELEMENT_TYPE.MENU,
            eventAction: AscTracking.ASC_MAPPINGS.EVENT_ACTION.CLICK,
        };
        AscTracking.trackInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MENU_INTERACTION, { detail: ascEventData }));
    });

    wts.visor.on(UI_EVENTS.TRACK_CLOSE_FORM_EVENT, function (e) {
        let inventoryID = e.data.inventoryID;
        let eventName = e.data.eventName;

        if (inventoryID) {
            getLabelAndDimensions(inventoryID, function (label, dimensions) {
                window.TrackEvent("Vehicle", eventName, label, dimensions);
            });
        }
        else {
            window.TrackEvent("Vehicle", eventName);
        }
        
        AscTracking.trackFormClose(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_FORM_ENGAGEMENT, { detail: e.data }));
    });

    wts.visor.on(UI_EVENTS.VEHICLE_DETAILS_TRACK_BRANDING_EVENT, function (e) {
        var eventName = e.data.eventName;
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        TrackEvent("Branding", eventName, label, dimensions);
    });

    wts.visor.on(UI_EVENTS.MY_GARAGE_GARAGE_EVENT, function (e) {
        var eventName = e.data.eventName;
        var value = e.data.value;
        TrackEvent("Garage", eventName, value);
    });

    wts.visor.on(UI_EVENTS.MY_GARAGE_VEHICLE_EVENT, function (e) {
        var eventName = e.data.eventName;
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        TrackEvent("Vehicle", eventName, label, dimensions);
    });

    wts.visor.on(UI_EVENTS.INVENTORY_LAYOUT_TRACK_SEARCH_EVENT, function (e) {
        var eventName = e.data.eventName;
        var value = e.data.value;

        window.TrackEvent("Search", eventName, value);

        var currentTarget = e.data.value.currentTarget;
        if (currentTarget) {
            AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: currentTarget }));
        }
    });

    wts.visor.on(UI_EVENTS.INVENTORY_LAYOUT_TRACK_LOCATOR_SEARCH_EVENT, function (e) {
        var eventName = e.data.eventName;
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        TrackEvent("Search", eventName, label, dimensions);
    });

    wts.visor.on(UI_EVENTS.SELECT_DEALER_LOCATOR_SEARCH, function (e) {
        var action = e.data.action;
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        window.TrackEvent("Dealer Locator Search", action, label, dimensions);
    });

    wts.visor.on(UI_EVENTS.SELECT_DEALER_LOCATOR_SEARCH_PAGE, function (e) {
        var searchPage = e.data;
        window.TrackEvent("Dealer Locator Search", "Go To Page", searchPage);
    });

    wts.visor.on(UI_EVENTS.SELECT_DEALER_LOCATOR_SEARCH_CONDITIONAL, function (e) {
        var eventName = e.data.eventName;
        var value = e.data.value;
        window.TrackEvent("DealerLocatorSearch", eventName, value);
    });

    wts.visor.on(UI_EVENTS.TRUCK_SEARCH_EVENT_CONDITIONAL, function (e) {
        var eventName = e.data.eventName;
        var value = e.data.value;
        var category = pageData.isVast ? "VAST" : "Search";
        TrackEvent(category, eventName, value);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }
    });

    wts.visor.on(UI_EVENTS.TRUCK_SEARCH_EVENT_VIN, function (e) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }
    });

   wts.visor.on(UI_EVENTS.MILES_SEARCH_CONDITIONAL, function (e) {
        var value = e.data.value + " Miles";
        var category = pageData.isVast ? "VAST" : "Search";
        TrackEvent(category, "Distance", value);

       var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
       if (adobePageData) {
           trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
       }
    });

    wts.visor.on(UI_EVENTS.LOCATION_SEARCH_CONDITIONAL, function (e) {
        var category = pageData.isVast ? "VAST" : "Search";
        TrackEvent(category, "Location Entry", e.data.value);
    });

    wts.visor.on(UI_EVENTS.TRUCK_SEARCH_ZIPCODE_CHANGE, function (e) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }
    });

    wts.visor.on(UI_EVENTS.VOCATION_SEARCH_CONDITIONAL, function (e) {
        var value = `Vocation: ${e.data.value}`;
        TrackEvent("Search", "Click Value", value);
    });

    wts.visor.on(UI_EVENTS.TRUCK_SEARCH_EVENT_NO_RESULTS, function (e) {
        var noResultsEventLabel = e.data.noResultsEventLabel;
        var category = pageData.isVast ? "VAST" : "Search";
        TrackEvent(category, "No Results", noResultsEventLabel, {});
    });

    wts.visor.on(UI_EVENTS.TRUCK_SEARCH_CLEAR_FILTERS, function (e) {
        var category = pageData.isVast ? "VAST" : "Search";
        TrackEvent(category, "Click Clear", "Clear Search Filters");

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.CLICK_VEHICLE_AD, function (e) {
        var label = e.data.label
        var dimensions = e.data.dimensions;
        TrackEvent(vehicleCategory, "Ad Click", label, dimensions);

        AscTracking.trackMediaInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_MEDIA_INTERACTION, { detail: e.data }));
    });

    wts.visor.on(UI_EVENTS.CLICK_RECENTLY_VIEWED, function (e) {
        var label = e.data.label;
        var dimensions = e.data.dimensions;
        window.TrackEvent(vehicleCategory, "Recently Viewed Click", label, dimensions);
    });

    wts.visor.on(UI_EVENTS.CLICK_TRUCK_SEARCH_FACETS_VAST, function (e) {
        var keyValue = e.data.keyValue;
        TrackEvent("VAST", "Click Value", keyValue);
    });

    wts.visor.on(UI_EVENTS.CLICK_SHOW_MY_INVENTORY_ON_VAST, function () {
        TrackEvent("VAST", "Click Value", "IncludeInventory: My Inventory");
    });

    wts.visor.on(UI_EVENTS.CLICK_SHOW_SISTER_INVENTORY_ON_VAST, function () {
        TrackEvent("VAST", "Click Value", "IncludeInventory: Sister Inventory");
    });

    wts.visor.on(UI_EVENTS.CLICK_SHOW_GROUP_INVENTORY_ON_VAST, function () {
        TrackEvent("VAST", "Click Value", "IncludeInventory: Group Inventory");
    });

    wts.visor.on(UI_EVENTS.CLICK_AVAILABLE_FOR_PURCHASE_TAB_ON_VAST, function () {
        TrackEvent("VAST", "Click Tab", "Available for Purchase");
    });

    wts.visor.on(UI_EVENTS.CLICK_WHOLE_WTS_NETWORK_TAB_ON_VAST, function () {
        TrackEvent("VAST", "Click Tab", "Whole WTS Network");
    });

    wts.visor.on(UI_EVENTS.CLICK_BRIGHTDROP_POOL_TAB_ON_VAST, function () {
        TrackEvent("VAST", "Click Tab", "Brightdrop Pool");
    });

    wts.visor.on(UI_EVENTS.OPEN_VEHICLE_ACQUISITION_DETAILS, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "View Acquisition Details", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_EMAIL_VAST_CONTACT, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "Email Acquisition Contact", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_CALL_VAST_CONTACT, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "Call Acquisition Contact", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_CALL_VAST_DEALER, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "Call Dealer", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_VAST_CONDITION_LINK, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "View Condition", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_VAST_AUCTION_LINK, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "View Auction", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.SUBMIT_VAST_MESSAGE, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            TrackEvent("VAST", "Message Acquisition Contact", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_VAST_OUTBOUND_LINK, function (e) {
        var inventoryID = e.data.inventoryID;
        var href = e.data.href;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent("VAST", "View Outbound Link", href, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_BACK_TO_SEARCH_RESULTS, function (e) {
        var inventoryID = e.data.inventoryID;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Close Details", label, dimensions);
        });

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }
    });

    wts.visor.on(UI_EVENTS.CLICK_BARE_CHASSIS_INQUIRY, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Bare Chassis Request", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_BODY_ONLY_INQUIRY, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Body Only Request", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.CLICK_SAVE_VEHICLE_TO_GARAGE, function (e) {
        var inventoryID = e.data;
        getLabelAndDimensions(inventoryID, function (label, dimensions) {
            window.TrackEvent(vehicleCategory, "Save To Garage", label, dimensions);
        });
    });


    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_STATE_OPEN_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Open Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_STATE_CLOSE_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Close Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_CHASSIS_OPEN_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Open Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_CHASSIS_CLOSE_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Close Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_BODY_OPEN_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Open Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_BODY_CLOSE_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Close Facet Header", label);

        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_ADDONS_OPEN_EVENT, function (e) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_ADDONS_CLOSE_EVENT, function (e) {
        var adobePageData = AdobeAnalytics.getAdobeInteractionClickEventData(e);
        if (adobePageData) {
            trackAdobeEvent(new CustomEvent("interaction-click", { detail: adobePageData }));
        }

        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_PROGRESSIVE_OPEN_EVENT, function (e) {
        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_PROGRESSIVE_CLOSE_EVENT, function (e) {
        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACET_OPEN_EVENT, function (e) {
        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACET_CLOSE_EVENT, function (e) {
        AscTracking.trackGeneralLayoutInteractionClick(new CustomEvent(AscTracking.ASC_MAPPINGS.EVENT.ASC_CTA_INTERACTION, { detail: e.data.currentTarget }));
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_TRAILER_OPEN_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Open Facet Header", label);
    });

    wts.visor.on(UI_EVENTS.VSP_FACETGROUP_TRAILER_CLOSE_EVENT, function (e) {
        var label = e.data.label;
        var category = pageData.isVast ? "VAST" : "Search";
        window.TrackEvent(category, "Close Facet Header", label);
    });

    wts.visor.on(UI_EVENTS.VAST_VSP_FACETGROUP_PARTNER_OPEN_EVENT, function (e) {
        if (pageData.isVast) {
            var label = e.data.label;
            window.TrackEvent("VAST", "Open Facet Header", label);
        }
    });

    wts.visor.on(UI_EVENTS.VAST_VSP_FACETGROUP_PARTNER_CLOSE_EVENT, function (e) {
        if (pageData.isVast) {
            var label = e.data.label;
            window.TrackEvent("VAST", "Close Facet Header", label);
        }
    });

    wts.visor.on(UI_EVENTS.NAVIGATION_PAGE_PARTNER_LEARN_MORE, function (e) {
        var label = `${getClientData("#dealer-data").dealerDescription}-Click Nav Page Partner Ad Learn More`;
        window.TrackEvent("Dealer Tools", "Navigation Page Clicks", label);
    });

    wts.visor.on(UI_EVENTS.NAVIGATION_PAGE_VIEW_ALL_PARTNERS, function (e) {
        var label = `${getClientData("#dealer-data").dealerDescription}-Click Nav Page View All Partners`;
        window.TrackEvent("Dealer Tools", "Navigation Page Clicks", label);
    });

    wts.visor.on(UI_EVENTS.MARKETPLACE_EVENT, function (e) {
        var category = e.data.category;
        var action = e.data.action;
        var label = e.data.label;

        window.TrackEvent(category, action, label);
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_TOGGLE, function (e) {
        window.TrackEvent("Catalog", "Commercial Catalog Toggle", e.data);
    });


    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_VIEW_BODY_LINE_LITERATURE_PDF, function (e) {
        window.TrackEvent("Catalog", "View Body Line Literature PDF", "Click " + e.data.Target, { dimension9: e.data.BodyType } );
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_VIEW_BODY_LINE_VIDEO, function (e) {
        window.TrackEvent("Catalog", "View Body Line Video", "Click " + e.data.BodyLine + " " + e.data.Source, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_START_REQUEST, function (e) {
        window.TrackEvent("Catalog", "Start Request", "Start " + e.data.BodyLine + " " + e.data.BodyType + " Custom Order Request", { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_VIEW_PHOTO, function (e) {
        window.TrackEvent("Catalog", "View Photo", "Click Photo " + e.data.BodyLine + " " + e.data.Source , { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_NEXT_PHOTO, function (e) {
        window.TrackEvent("Catalog", "View Next Photo", "View Next Photo " + e.data.BodyLine + ' - ' + e.data.URL, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_PREV_PHOTO, function (e) {
        window.TrackEvent("Catalog", "View Previous Photo", "View Next Photo " + e.data.BodyLine + ' - ' + e.data.URL, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_CHANGE_BODY_TYPE, function (e) {
        window.TrackEvent("Catalog", "Change Body Type", "Click " + e.data, { dimension9: e.data});
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_CLICK_BODY_LINE, function (e) {
        window.TrackEvent("Catalog", "Select Body Line", "Click " + e.data.BodyManufacturer + " " + e.data.BodyLine, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_NEXT, function (e) {
        window.TrackEvent("Catalog", "Page Thumbnails Next", "Page Thumbnails Next " + e.data.BodyLine, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_CLICK_PAGE_THUMBNAILS_PREVIOUS, function (e) {
        window.TrackEvent("Catalog", "Page Thumbnails Previous", "Page Thumbnails Previous " + e.data.BodyLine, { dimension9: e.data.BodyType });
    });

    wts.visor.on(UI_EVENTS.COMMERCIAL_CATALOG_CLICK_SHOW_MORE, function (e) {
        window.TrackEvent("Catalog", "Show More", "Show More" + " " + e.data.BodyLine, {dimension9: e.data.BodyType});
    });

    wts.visor.on(UI_EVENTS.CONDITIONAL_CALL_TO_ACTION, function (e) {
        if (e.data) {
            var el = e.data;
            let category = el.getAttribute("category");
            let action = el.getAttribute("action");
            let label = el.getAttribute("label");

            window.TrackEvent(category, action, label);
        }
    });

    wts.visor.on(UI_EVENTS.RESOURCE_RACK_LAUNCH_PAGE, function (e) {
        window.TrackEvent("Resource Rack", "Navigation Launch", null, { ...e.data, ActionSubType: 'Navigation Launch Resource Rack' });
    });
    
    wts.visor.on(UI_EVENTS.RESOURCE_RACK_CHANGE_SEARCH_CONTROLS, function (e) {
        window.TrackEvent("Resource Rack", "Search", null, e.data );
    });
   
    wts.visor.on(UI_EVENTS.RESOURCE_RACK_PREVIEW_LINK_CLICK, function (e) {
        window.TrackEvent("Resource Rack", "Preview Link Click", null, e.data);
    });
   
    wts.visor.on(UI_EVENTS.RESOURCE_RACK_ACTION_MENU_GET_LINK, function (e) {
        window.TrackEvent("Resource Rack", "Get Link", null, e.data);
    });
    
    wts.visor.on(UI_EVENTS.RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_COPY_LINKS, function (e) {
        window.TrackEvent("Resource Rack", "Copy Links", null, e.data);
    });
    
    wts.visor.on(UI_EVENTS.RESOURCE_RACK_MULTISELECT_FOOTER_ACTION_START_PROSPECTING, function (e) {
        window.TrackEvent("Resource Rack", "Start Prospecting", null, e.data);
    });


    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_LAUNCH_PAGE, function (e) {
        window.TrackEvent("Tracking Links History", "Navigation Launch", null, { ...e.data, Version: 'V1' });
    });
    //Create and submit have been hidden from page for time being
    //wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CREATE_TRACKING_LINK, function (e) {
    //    window.TrackEvent("Tracking Links History", "Launch Create Tracking Link");
    //});

    //wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_SUBMIT_TRACKING_LINK, function (e) {
    //    window.TrackEvent("Tracking Links History", "Create Tracking Link Submit");
    //});
    
    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CLICK_DETAILS, function (e) {
        window.TrackEvent("Tracking Links History", "View Details", null, {...e.data, Version: 'V1'});
    });
    
    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CLICK_EDIT_TRACKING_LINK, function (e) {
        window.TrackEvent("Tracking Links History", "Launch Edit Link", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CLICK_SAVE_EDIT, function (e) {
        window.TrackEvent("Tracking Links History", "Edit Link Submit", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CLICK_DISABLE_LINK, function (e) {
        window.TrackEvent("Tracking Links History", "Disable Link", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.TRACKING_LINKS_HISTORY_CLICK_COPY_LINK, function (e) {
        window.TrackEvent("Tracking Links History", "Copy Link", null, { ...e.data, Version: 'V1' });
    });

    ////Todo - Investigate AddTrackingInfo already present in Email
    //wts.visor.on(UI_EVENTS.TRACKING_LINKS_EMAIL_CLICK_SEE_LINKS, function (e) {
    //    window.TrackEvent("Tracking Links Email", "See Tracking Links");
    //});

    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_LAUNCH_PAGE, function (e) {
        window.TrackEvent("Invoice Binder", "Navigation Launch", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_SEARCH, function (e) {
        window.TrackEvent("Invoice Binder", "Search", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_ON_COUNT, function (e) {
        window.TrackEvent("Invoice Binder", "Click Missing Invoices", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_VIEW_LISTING_DETAILS, function (e) {
        window.TrackEvent("Invoice Binder", "View Listing", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_MARK_IF_NOT_UPFIT, function (e) {
        window.TrackEvent("Invoice Binder", "Mark it Not Upfit", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_WINDOW_STICKER, function (e) {
        window.TrackEvent("Invoice Binder", "View Window Sticker", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_INVOICE_LINK, function (e) {
        window.TrackEvent("Invoice Binder", "View Invoice", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_UPLOAD_INVOICES, function (e) {
        window.TrackEvent("Invoice Binder", "Upload Invoice", null, { ...e.data, Version: 'V1' });
    });
    
    wts.visor.on(UI_EVENTS.INVOICE_BINDER_CLICK_DELETE_INVOICE, function (e) {
        window.TrackEvent("Invoice Binder", "Delete Invoice", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.PRINTING_ACTION_PRINT_COMPLETE_LISTING, function (e) {
        window.TrackEvent("Print Listing", "Print Complete Listing", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.PRINTING_ACTION_PRINT_UPFIT_WINDOW_STICKER, function (e) {
        window.TrackEvent("Print Window Sticker", "Print Upfit Window Sticker", null, { ...e.data, Version: 'V1' });
    });

    /**
     * Inventory Management
     */
    // General
    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_GROUP_SELECT_MEMBER_DEALER, function (e) {
        window.TrackEvent("Inventory Management", "General", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_EXPORT_LISTINGS, function (e) {
        window.TrackEvent("Inventory Management", "General", null, { ...e.data, Version: 'V1' });
    });

    // Create Listing
    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CREATE_BODY_ONLY_LISTING, function (e) {
        window.TrackEvent("Inventory Management", "Create Listing", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CREATE_TRAILER_LISTING, function (e) {
        window.TrackEvent("Inventory Management", "Create Listing", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CREATE_VEHICLE_LISTING, function (e) {
        window.TrackEvent("Inventory Management", "Create Listing", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_TOTAL_LISTINGS, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    // Inventory Summary
    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_ON_SALE_LISTINGS, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_FEATURED_LISTINGS, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_HIDDEN_LISTINGS, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_PRIVATE_LISTINGS, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_VAST_ONLY_LISTINGS, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_UNKNOWN_IF_UPFIT, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_MISSING_PHOTOS, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_INVALID_PHOTOS, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_NO_INVOICES, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_MANUAL_LISTINGS, function (e) {
        window.TrackEvent("Inventory_Management", "Inventory Summary", null, { ...e.data, Version: 'V1' });
    });

    // Inventory Search
    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_RUN_LAST_QUERY, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });
   wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_TOGGLE_ADVANCED_SEARCH, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_TEXT_SEARCH, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_FILTER_INVENTORY_SELECT, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_FILTER_INVENTORY_CHECKBOX, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_RESET_FILTERS, function (e) {
        window.TrackEvent("Inventory Management", "Inventory Search", null, { ...e.data, Version: 'V1' });
    });

    // Action Menu
    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_VIEW_INVOICES, function (e) {
        window.TrackEvent("Inventory Management", "Action Menu", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_EDIT_PRICING, function (e) {
        window.TrackEvent("Inventory Management", "Action Menu", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_EDIT_TRADE_DETAILS, function (e) {
        window.TrackEvent("Inventory Management", "Action Menu", null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_EDIT_LISTING, function (e) {
        window.TrackEvent('Inventory Management', 'Action Menu', null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_MARK_AS_MOVED, function (e) {
        window.TrackEvent('Inventory Management', 'Action Menu', null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.INVENTORY_MANAGEMENT_CLICK_DELETE_LISTING, function (e) {
        window.TrackEvent('Inventory Management', 'Action Menu', null, { ...e.data, Version: 'V1' });
    });

    wts.visor.on(UI_EVENTS.VIDEO_PLAYER_START, function (e) {
        window.TrackEvent('Youtube Video Player Start', 'VDP', e.data.label, { ...e.data });
    });

    wts.visor.on(UI_EVENTS.VIDEO_PLAYER_RESUME, function (e) {
        window.TrackEvent('Youtube Video Player Resume', 'VDP', e.data.label, { ...e.data });
    });

    wts.visor.on(UI_EVENTS.VIDEO_PLAYER_PAUSE, function (e) {
        window.TrackEvent('Youtube Video Player Pause', 'VDP', e.data.label, { ...e.data });
    });

    wts.visor.on(UI_EVENTS.VIDEO_PLAYER_THRESHOLD, function (e) {
        window.TrackEvent('Youtube Video Player Threshold', 'VDP', e.data.label, { ...e.data });
    });

    wts.visor.on(UI_EVENTS.READ_MORE_VEHICLE_NOTES_CLICK, function (e) {
        getLabelAndDimensions(e.data, function (label, dimensions) {
            window.TrackEvent("Vehicle", "Read More Vehicle Notes", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.READ_LESS_VEHICLE_NOTES_CLICK, function (e) {
        getLabelAndDimensions(e.data, function (label, dimensions) {
            window.TrackEvent("Vehicle", "Read Less Vehicle Notes", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.VIEW_ALL_VEHICLE_OPTIONS_CLICK, function (e) {
        getLabelAndDimensions(e.data, function (label, dimensions) {
            window.TrackEvent("Vehicle", "View All Vehicle Options", label, dimensions);
        });
    });

    wts.visor.on(UI_EVENTS.SEE_DEALERSHIPS_OTHER_LISTINGS_CLICK, function (e) {
        getLabelAndDimensions(e.data, function (label, dimensions) {
            window.TrackEvent("Vehicle", "See Dealership's Other Listings", label, dimensions);
        });
    });

    //Todo - Hook these up to PDF Viewer without wts context
    //wts.visor.on(UI_EVENTS.PDF_VIEWER_INTERNAL_LOADING, function (e) {
    //    window.TrackEvent("PDF Viewer", "Internal PDF Preview", null, { ...e.data, Version: 'V1' });
    //});
    
    //wts.visor.on(UI_EVENTS.PDF_VIEWER_CLICK_GET_SHAREABLE_LINK, function (e) {
    //    window.TrackEvent("PDF Viewer", "Get Shareable Link", null, { ...e.data, Version: 'V1' });
    //});
    
    //wts.visor.on(UI_EVENTS.PDF_VIEWER_CLICK_GET_TRACKING_LINK, function (e) {
    //    window.TrackEvent("PDF Viewer", "Get Tracking Link", null, { ...e.data, Version: 'V1' });
    //});


    /**
     * Hides away the details of fetching the label and dimensions
     * 
     * @description The VDP and VSP fetch the labels and dimensions from different window-attached objects.
     *  - VDP retrieves it directly via myAnalyticsLabel/myAnalyticsDimensions
     *  - VSP uses a lookup table via analyticsLabels/analyticsDimensions
     * @param {string} inventoryID an inventoryID
     * @param {Function} callback A function that will have two parameters: label, dimensions
     * @returns {undefined}
     */
    function getLabelAndDimensions(inventoryID, callback) {

        if (!inventoryID) {
            return;
        }

        var label = "";
        var vin = null;
        var customDimensions = null;

        // vsp
        if (window.analyticsLabels && inventoryID in window.analyticsLabels) {
            label += window.analyticsLabels[inventoryID];
        }

        // vdp
        if (window.myAnalyticsLabel) {
            label += window.myAnalyticsLabel;
        }

        if (window.myAnalyticsDimensions) {
            customDimensions = window.myAnalyticsDimensions;
            vin = customDimensions["dimension6"] || null;
        }

        // Order matter a lot here. window.myAnalyticsDimensions is always going to be defined so we will check for the VSP specific version
        // to override the previous if statement
        if (window.analyticsDimensions && inventoryID in window.analyticsDimensions) {
            customDimensions = window.analyticsDimensions[inventoryID];
            vin = customDimensions["dimension6"] || null;
        }

        if (vin !== null) {
            label += " - " + vin;
        }

        callback(label, customDimensions);
    }
})(window.wts, window.wts.modules);
;
wts.registerBundle("marketing");
(function (wts, modules) {   

    /**
     * @module MarketingEvents
     * */

    /**
     * @const {object} */
    var events = {
        vehicleLead: "Vehicle:Lead",
        vehicleView: "Vehicle:View"
    };

    /**
     * Exposes an api to attach event handlers for marketing related events.
     * Exposes an api to trigger marketing related events.
     * @class MarketingEvents
     * @param {EventEmitter} eventEmitter An instance of `EventEmitter` @see {module:EventEmitter}
     * @returns {MarketingEvents} An instance of `MarketingEvents`
     * @example
     * modules.MarketingEvents.onVehicleLead(function(eventArgs) {//Do important things with eventArgs.data});
     * @example
     * var inventoryId = 12345;
     * modules.MarketingEvents.vehicleLead(new modules.VehicleLeadData(inventoryId));
     * */
    function MarketingEvents(eventEmitter) {
        if (!(eventEmitter instanceof modules.EventEmitter)) {
            throw "eventEmitter must be an `EventEmitter`";
        }

        this.eventEmitter = eventEmitter;
        
        return this;
    }

    /** 
     *  Handles the vehicle lead event
     *  @callback VehicleLeadCallback
     *  @param {Object} eventArgs where eventArgs.data is `VehicleLeadData`
     * */

    /**
     * Handles the vehicle viewed event
     * @callback VehicleViewCallback
     * @param {Object} eventArgs where eventArgs.data is `VehicleViewData`
     * */



    MarketingEvents.prototype = {
        /**
         * @description the collection of active marketing event related promises
         * @type {Array<Jquery.Deferred>}
         */
        activePromises: [],

        /**
         * @description the collection of inventory details request promises, keyed to inventory id.
         * @type {Array<JQuery.Deferred<VehicleViewData>>}
         */
        inventoryPromises: [],

        /**
         * @description returns a Deferred (@see Jquery.Deferred)  that resolves when all activePromises (from marketing events) have resolved.
         * @returns {JQuery.Deferred} the deferred
         */
        wait: function() {
            return $.when.apply($, this.activePromises);
        },

        /**
         * Adds an event handler callback for the `VehicleLead` event
         * @param {VehicleLeadCallback} callback - the event handler
         * @param {any} context the context to apply the event handler (aka 'this' in the handler scope)
         * @returns {void}
         * */
        onVehicleLead: function (callback, context) {
            this.eventEmitter.on(events.vehicleLead, callback, context);
        },

        /**
         * Adds an event handler for the `VehicleView` event
         * @param {VehicleViewCallback} callback - the event handler
         * @param {any} context the context to apply the event handler (aka 'this' in the handler scope)
         * @returns {void}
         */
        onVehicleView: function (callback, context) {
            this.eventEmitter.on(events.vehicleView, callback, context);
        },

        /**
         * Triggers the `VehicleLead` event
         * @param {VehicleLeadData} vehicleLeadData the `VehicleLeadData` event object
         * @throws {Error} if parameter not an instance of VehicleLeadData
         * @returns {void}
         */
        vehicleLead: function (vehicleLeadData) {
            if (vehicleLeadData instanceof VehicleLeadData) {
                this.eventEmitter.trigger(events.vehicleLead, vehicleLeadData);
            }
            else {
                throw "parameter vehicleLeadData is not an instance of `VehicleLeadData`";
            }
        },

        /**
         * Triggers the `VehicleView` event
         * @param {VehicleViewData} vehicleViewData the `VehicleViewData` event object
         * @throws {Error} if parameter not an instance of VehicleViewData
         * @returns {void}
         */
        vehicleView: function (vehicleViewData) {
            if (vehicleViewData instanceof VehicleViewData) {
                this.eventEmitter.trigger(events.vehicleView, vehicleViewData);
            }
            else {
                throw "parameter vehicleViewData is not an instance of `VehicleViewData`";
            }
        },

        /**
         * retrieves the `VehicleViewData` from an api endpoint and caches it as a promise resolving to the data
         * @param {string} inventoryId the inventory id for the vehicle
         * @param {Function} callback the function to call after the vehicle data is retrieved
         * @returns {Promise} the vehicle instance `VehicleViewData`
         */
        getVehicleData: function (inventoryId, callback) {
            var that = this;

            // Create and cache the request promise
            if (!this.inventoryPromises[inventoryId]) {
                this.inventoryPromises[inventoryId] = $.get("/api/marketing/vehicledata/" + inventoryId)
                    .fail(function (resp) {
                        // Do we have a standardized way of handling these things??
                    });
            }

            // capture the promise that resolves after the callback into activePromises and remove it after the callback
            var def = this.inventoryPromises[inventoryId].then(function(data) {
                callback(data);
                that.activePromises = that.activePromises.filter(function (value) {
                    return value !== def;
                });
            });

            this.activePromises.push(def);
        }
    };

    /**
     * VehicleLeadData holds information relevant to the vehicle lead event
     * @class VehicleLeadData
     * @param {string} inventoryId - the vehicle inventory id
     * @returns {VehicleLeadData} an instance of `VehicleLeadData`
     */
    function VehicleLeadData(inventoryId) {
        this.inventoryId = inventoryId;

        return this;
    }

    /**
     * @class VehicleViewData
     * @param {string} inventoryId the vehicle's inventory id
     * @param {number} dealerNumericId the vehicle's dealer numeric id
     * @param {string} zipCode the dealer's zipcode
     * @param {string} make the vehicle's make, e.g. Ford
     * @param {string} model the vehicle's model, e.g. F-150
     * @param {number} year the vehicle's model year, e.g. 2020
     * @param {string} stockType 'New' or 'Used'
     * @param {string} color the vehicle's exterior color
     * @param {string} transmission the vehicle's transmission type, e.g. Automatic
     * @param {string} bodyStyle the vehicle's body style, 'Van' or 'Truck'
     * @param {string} fuelType the vehicle's fuel type, 'Gas' or 'Diesel'
     * @param {string} drivetrain the vehicle's drivetrain, e.g. 4x2
     * @param {number} price the vehicle's 'final price' after discounts at the time of view
     * @param {string} trim the vehicle's trim package
     * @param {number} mileage the vehicle's mileage
     * @param {string} vin the vehicle's vin number
     * @param {string} fuelType the vehicle's fuel type
     * @return {VehicleViewData} an instance of `VehicleViewData`
     */
    function VehicleViewData(
        inventoryId,
        dealerNumericId,
        zipCode,
        make,
        model,
        year,
        stockType,
        color,
        transmission,
        bodyStyle,
        fuelType,
        drivetrain,
        price,
        trim,
        mileage,
        vin,
        fuelType
        )    {        
            this.inventoryId = inventoryId;
            this.dealerNumericId = dealerNumericId;
            this.zipCode = zipCode;
            this.make = make;
            this.model = model;
            this.year = year;
            this.stockType = stockType;
            this.color = color;
            this.transmission = transmission;
            this.bodyStyle = bodyStyle;
            this.fuelType = fuelType;
            this.drivetrain = drivetrain;
            this.price = price;
            this.trim = trim;
            this.mileage = mileage;
            this.vin = vin;
            this.fuelType = fuelType;
    }

    // Singleton marketing events object
    modules.MarketingEvents = new MarketingEvents(new modules.EventEmitter());

    // constructors for tracking data objects
    modules.VehicleLeadData = VehicleLeadData;
    modules.VehicleViewData = VehicleViewData;

})(window.wts,window.wts.modules);;
(function (wts, modules) {

    
    /** 
      * @class FacebookMarketingEvents
      * @param {MarketingEvents} marketingEvents a `MarketingEvents` object
      * @returns {void}
      */    
    function FacebookPixel(marketingEvents) {
        if (typeof marketingEvents === "undefined") {
            throw "MarketingEvents dependency not found";
        }

        this.marketingEvents = marketingEvents;

        return this;
    }

    FacebookPixel.prototype = {

        /**
         * Initializes facebook pixel with pixelId
         * @param {string} pixelId The dealer's facebook pixel id
         * @returns {void}
         */
        init: function (pixelId) {
            /**
             * Facebook Pixel injection script from: https://
             * */
            (function (f, b, e, v, n, t, s) {
                if (f.fbq) {
                    return;
                } n = f.fbq = function () {
                    n.callMethod ?
                        n.callMethod.apply(n, arguments) : n.queue.push(arguments);
                };
                if (!f._fbq) {
                    f._fbq = n;
                } n.push = n; n.loaded = !0; n.version = "2.0";
                n.queue = []; t = b.createElement(e); t.async = !0;
                t.src = v; s = b.getElementsByTagName(e)[0];
                s.parentNode.insertBefore(t, s);
            })(window, document, "script",
                "https://connect.facebook.net/en_US/fbevents.js");

            this.pixel = window.fbq;

            this.marketingEvents.onVehicleView(this.vehicleViewHandler, this);
            this.marketingEvents.onVehicleLead(this.vehicleLeadHandler, this);

            this.pixel("init", pixelId);
            this.pixel("track", "PageView");
        },

        /**
         * Sends a pixel 'lead' event to facebook 
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @returns {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleLeadHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleLeadData)) {
                throw "eventArgs.data must be a `VehicleLeadData`, see MarketingEvents module";
            }

            var vehicleLeadData = eventArgs.data;
            var that = this;

            this.marketingEvents.getVehicleData(vehicleLeadData.inventoryId, function (vehicleViewData) {
                var facebookPixelVehicleData = that.mapVehicleData(vehicleViewData);

                // Track the lead, yea!
                that.pixel("track", "Lead", facebookPixelVehicleData);
            });            
        },

        /**
         * Composes the event object for the viewed vehicle and calls the Facebook Pixel 'ViewContent' event
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @return {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleViewHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleViewData)) {
                throw "eventArgs.data must be a `VehicleViewData`, see MarketingEvents module";
            }

            var facebookPixelVehicleData = this.mapVehicleData(eventArgs.data);
                        
            this.pixel("track", "ViewContent", facebookPixelVehicleData);
        },

        /**
         * Maps vehicle data from the event to facebook pixel's schema
         * @param {VehicleViewData} vehicleViewData the `VehicleViewData` to map
         * @returns {Object} the mapped FacebookPixelVehicleData
         */
        mapVehicleData: function (vehicleViewData) {
            var drivetrain = "";

            switch (vehicleViewData.drivetrain) {
                case "4x2": drivetrain = "RWD"; break;
                case "4x4": drivetrain = "FOUR_WD"; break;
                default: drivetrain = "TWO_WD"; break;
            }

            // See: https://developers.facebook.com/docs/marketing-api/dynamic-ads-auto/auto-event/
            var facebookPixelVehicleData = {
                content_type: "vehicle", // REQUIRED: DO NOT change this, must be set to 'vehicle'
                content_ids: [vehicleViewData.dealerNumericId], // REQUIRED: array of vehicle IDs
                postal_code: vehicleViewData.zipCode, // RECOMMENDED
                country: "United States", // RECOMMENDED  don't use abbreviations
                make: vehicleViewData.make, // RECOMMENDED
                model: vehicleViewData.model, // RECOMMENDED
                year: vehicleViewData.year, // RECOMMENDED
                state_of_vehicle: vehicleViewData.stockType, // RECOMMENDED
                exterior_color: vehicleViewData.color, // RECOMMENDED
                transmission: vehicleViewData.transmission, // RECOMMENDED
                body_style: vehicleViewData.bodyStyle, // RECOMMENDED
                fuel_type: vehicleViewData.fuelType, // RECOMMENDED
                drivetrain: drivetrain, // RECOMMDENDED
                price: vehicleViewData.price, // RECOMMENDED, up to 2 decimals optional
                currency: "USD", // REQUIRED if price and preferred_price_range is used 
                // preferred_price_range: '[10000,20000]' // Optional up to two decimals, min,max
                trim: vehicleViewData.trim,
                "mileage.value": vehicleViewData.mileage,
                "mileage.unit": "MI",
                vin: vehicleViewData.vin,
                value: 50
            };

            return facebookPixelVehicleData;
        }
    };

    modules.FacebookPixel = new FacebookPixel(modules.MarketingEvents);

})(window.wts, window.wts.modules);;
(function (wts, modules) {
    
    /** 
      * @class GoogleAdwordsEvents
      * @param {MarketingEvents} marketingEvents a `MarketingEvents` object
      * @returns {void}
      */    
    function GoogleAdwords(marketingEvents) {
        if (typeof marketingEvents === "undefined") {
            throw "MarketingEvents dependency not found";
        }

        this.marketingEvents = marketingEvents;

        return this;
    }

    GoogleAdwords.prototype = {

        /**
         * Init initializes google adwords with the adwords id
         * @param {string} awId The dealer's adwords id
         * @returns {void}
         */
        init: function (awId, awConversionCode) {

            this.marketingEvents.onVehicleView(this.vehicleViewHandler, this);
            this.marketingEvents.onVehicleLead(this.vehicleLeadHandler, this);

            // Google defined pieces
            // the processing on this is 
            window.dataLayer = window.dataLayer || [];
            this.gtag = function () {
                window.dataLayer.push(arguments);
            };

            this.adWordsId = awId;
            this.gtag("js", new Date());
            this.gtag("config", awId);
            this.awConversionCode = awConversionCode
        },

        /**
         * Sends a 'purchase' event to google remarketing when a lead is generated
         * Also sends a 'conversion' event for google adwords conversion tracking
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @returns {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleLeadHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleLeadData)) {
                throw "eventArgs.data must be a `VehicleLeadData`, see MarketingEvents module";
            }

            var vehicleLeadData = eventArgs.data;
            var that = this;

            this.marketingEvents.getVehicleData(vehicleLeadData.inventoryId, function (vehicleViewData) {
                // Track the lead, yea!
                var adwordsData = that.mapVehicleData(vehicleViewData);

                // Google adwords remarketing event
                that.gtag("event", "purchase", adwordsData);

                // Google adwords conversion tracking event
                that.gtag("event", "conversion", { "send_to": that.adWordsId + "/" + that.awConversionCode, "event_callback": function () { } });
            });      
            // Comvoy Conversion Code = "/ElITCLvnhroBEJjDjOQC"
        },

        /**
         * Composes the event object for the viewed vehicle and calls the Google AdWords remarketing event event
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @return {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleViewHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleViewData)) {
                throw "eventArgs.data must be a `VehicleViewData`, see MarketingEvents module";
            }

            var adwordsData = this.mapVehicleData(eventArgs.data);
                        
            this.gtag("event", "view_item", adwordsData);
        },

        /**
         * Maps from `VehicleViewData` to google's remarketing object 
         * @param {VehicleViewData} vehicleViewData the `VehicleViewData` to map
         * @returns {any} the google adwords remarketing object
         */
        mapVehicleData: function (vehicleViewData) {
            // See: https://support.google.com/google-ads/answer/7305793
            var adwordsData = {
                value: vehicleViewData.price,
                items: [{
                    id: vehicleViewData.dealerNumericId,
                    // location_id: TBD - could use the dealer ID here
                    google_business_vertical: "custom"
                }]
            };

            return adwordsData;
        }
    };

    modules.GoogleAdwords = new GoogleAdwords(modules.MarketingEvents);

})(window.wts, window.wts.modules);;
(function (wts, modules) {
   
    /** 
      * @class BingUET
      * @param {MarketingEvents} marketingEvents a `MarketingEvents` object
      * @returns {void}
      */    
    function BingUET(marketingEvents) {
        if (typeof marketingEvents === "undefined") {
            throw "MarketingEvents dependency not found";
        }

        this.marketingEvents = marketingEvents;

        return this;
    }

    BingUET.prototype = {

        /**
         * Init initializes bing uet
         * @param {string} uetTagId The Universal Event Tracking tag id
         * @returns {void}
         */
        init: function (uetTagId) {

            var that = this;

            var bing = function (w, d, t, r, u, id) {
                var f, n, i; that[u] = w[u] = w[u] || [],
                    f = function () {
                        var o = { ti: id };
                        o.q = w[u],
                            w[u] = new UET(o),
                        w[u].push("pageLoad"),
                        that[u] = w[u];
                    },
                    n = d.createElement(t),
                    n.src = r,
                    n.async = 1,
                    n.onload = n.onreadystatechange = function () {
                        var s = this.readyState;
                        s && s !== "loaded" && s !== "complete" || (f(), n.onload = n.onreadystatechange = null);
                    },
                    i = d.getElementsByTagName(t)[0],
                    i.parentNode.insertBefore(n, i);
            };

            bing(window, document, "script", "//bat.bing.com/bat.js", "uetq", uetTagId);

            // Connect marketing events
            this.marketingEvents.onVehicleView(this.vehicleViewHandler, this);
            this.marketingEvents.onVehicleLead(this.vehicleLeadHandler, this);
        },

        /**
         * Sends a Bing Custom Event       
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @returns {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleLeadHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleLeadData)) {
                throw "eventArgs.data must be a `VehicleLeadData`, see MarketingEvents module";
            }

            var vehicleLeadData = eventArgs.data;
            var that = this;

            this.marketingEvents.getVehicleData(vehicleLeadData.inventoryId, function (vehicleViewData) {

                var bingData = that.mapVehicleData(vehicleViewData);

                bingData.ecomm_pagetype = "purchase";

                var vehicleData = Object.assign({ "event_category": "Remarketing"}, bingData);

                that.uetq.push("event", "generated_lead", vehicleData);
            });            
        },

        /**
         * Composes the event object for the viewed vehicle and calls the Bing UET Custom Event
         * @param {Object} eventArgs the event arguments, @see EventEmitter.dispatchEvent
         * @return {void}
         * @throws {string} If `eventArgs.data` is not a `VehicleLeadData`
         */
        vehicleViewHandler: function (eventArgs) {
            if (!(eventArgs.data instanceof modules.VehicleViewData)) {
                throw "eventArgs.data must be a `VehicleViewData`, see MarketingEvents module";
            }

            var bingData = this.mapVehicleData(eventArgs.data);

            bingData.ecomm_pagetype = "product";

            var vehicleData = Object.assign({ "event_category": "Remarketing"}, bingData);
                        
            this.uetq.push("event", "view_item", vehicleData);
        },

        /**
         * Maps from `VehicleViewData` to google's remarketing object 
         * @param {VehicleViewData} vehicleViewData the `VehicleViewData` to map
         * @returns {any} the bing remarketing object
         */
        mapVehicleData: function (vehicleViewData) {
            // See: https://support.google.com/google-ads/answer/7305793
            var bingData = {
                "content_type": "vehicle",
                "ecomm_prodid": [vehicleViewData.dealerNumericId]
            };

            return bingData;
        }
    };

    modules.BingUET = new BingUET(modules.MarketingEvents);

})(window.wts, window.wts.modules);;
