Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/cartforge.co/pub/static/frontend/Smartwave/porto/en_US/js/bundle/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/cartforge.co/pub/static/frontend/Smartwave/porto/en_US/js/bundle/bundle5.js
require.config({"config": {
        "jsbuild":{"jquery/ui-modules/i18n/datepicker-eo.js":"/* Esperanto initialisation for the jQuery UI date picker plugin. */\n/* Written by Olivier M. ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.eo = {\n\tcloseText: \"Fermi\",\n\tprevText: \"&#x3C;Anta\",\n\tnextText: \"Sekv&#x3E;\",\n\tcurrentText: \"Nuna\",\n\tmonthNames: [ \"Januaro\", \"Februaro\", \"Marto\", \"Aprilo\", \"Majo\", \"Junio\",\n\t\"Julio\", \"A\u016dgusto\", \"Septembro\", \"Oktobro\", \"Novembro\", \"Decembro\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\",\n\t\"Jul\", \"A\u016dg\", \"Sep\", \"Okt\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Diman\u0109o\", \"Lundo\", \"Mardo\", \"Merkredo\", \"\u0134a\u016ddo\", \"Vendredo\", \"Sabato\" ],\n\tdayNamesShort: [ \"Dim\", \"Lun\", \"Mar\", \"Mer\", \"\u0134a\u016d\", \"Ven\", \"Sab\" ],\n\tdayNamesMin: [ \"Di\", \"Lu\", \"Ma\", \"Me\", \"\u0134a\", \"Ve\", \"Sa\" ],\n\tweekHeader: \"Sb\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.eo );\n\nreturn datepicker.regional.eo;\n\n} );\n","jquery/ui-modules/i18n/datepicker-hy.js":"/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Levon Zakaryan ([email protected])*/\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.hy = {\n\tcloseText: \"\u0553\u0561\u056f\u0565\u056c\",\n\tprevText: \"&#x3C;\u0546\u0561\u056d.\",\n\tnextText: \"\u0540\u0561\u057b.&#x3E;\",\n\tcurrentText: \"\u0531\u0575\u057d\u0585\u0580\",\n\tmonthNames: [ \"\u0540\u0578\u0582\u0576\u057e\u0561\u0580\", \"\u0553\u0565\u057f\u0580\u057e\u0561\u0580\", \"\u0544\u0561\u0580\u057f\", \"\u0531\u057a\u0580\u056b\u056c\", \"\u0544\u0561\u0575\u056b\u057d\", \"\u0540\u0578\u0582\u0576\u056b\u057d\",\n\t\"\u0540\u0578\u0582\u056c\u056b\u057d\", \"\u0555\u0563\u0578\u057d\u057f\u0578\u057d\", \"\u054d\u0565\u057a\u057f\u0565\u0574\u0562\u0565\u0580\", \"\u0540\u0578\u056f\u057f\u0565\u0574\u0562\u0565\u0580\", \"\u0546\u0578\u0575\u0565\u0574\u0562\u0565\u0580\", \"\u0534\u0565\u056f\u057f\u0565\u0574\u0562\u0565\u0580\" ],\n\tmonthNamesShort: [ \"\u0540\u0578\u0582\u0576\u057e\", \"\u0553\u0565\u057f\u0580\", \"\u0544\u0561\u0580\u057f\", \"\u0531\u057a\u0580\", \"\u0544\u0561\u0575\u056b\u057d\", \"\u0540\u0578\u0582\u0576\u056b\u057d\",\n\t\"\u0540\u0578\u0582\u056c\", \"\u0555\u0563\u057d\", \"\u054d\u0565\u057a\", \"\u0540\u0578\u056f\", \"\u0546\u0578\u0575\", \"\u0534\u0565\u056f\" ],\n\tdayNames: [ \"\u056f\u056b\u0580\u0561\u056f\u056b\", \"\u0565\u056f\u0578\u0582\u0577\u0561\u0562\u0569\u056b\", \"\u0565\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b\", \"\u0579\u0578\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b\", \"\u0570\u056b\u0576\u0563\u0577\u0561\u0562\u0569\u056b\", \"\u0578\u0582\u0580\u0562\u0561\u0569\", \"\u0577\u0561\u0562\u0561\u0569\" ],\n\tdayNamesShort: [ \"\u056f\u056b\u0580\", \"\u0565\u0580\u056f\", \"\u0565\u0580\u0584\", \"\u0579\u0580\u0584\", \"\u0570\u0576\u0563\", \"\u0578\u0582\u0580\u0562\", \"\u0577\u0562\u0569\" ],\n\tdayNamesMin: [ \"\u056f\u056b\u0580\", \"\u0565\u0580\u056f\", \"\u0565\u0580\u0584\", \"\u0579\u0580\u0584\", \"\u0570\u0576\u0563\", \"\u0578\u0582\u0580\u0562\", \"\u0577\u0562\u0569\" ],\n\tweekHeader: \"\u0547\u0532\u054f\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.hy );\n\nreturn datepicker.regional.hy;\n\n} );\n","jquery/ui-modules/i18n/datepicker-bs.js":"/* Bosnian i18n for the jQuery UI date picker plugin. */\n/* Written by Kenan Konjo. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.bs = {\n\tcloseText: \"Zatvori\",\n\tprevText: \"&#x3C;\",\n\tnextText: \"&#x3E;\",\n\tcurrentText: \"Danas\",\n\tmonthNames: [ \"Januar\", \"Februar\", \"Mart\", \"April\", \"Maj\", \"Juni\",\n\t\"Juli\", \"August\", \"Septembar\", \"Oktobar\", \"Novembar\", \"Decembar\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Nedelja\", \"Ponedeljak\", \"Utorak\", \"Srijeda\", \"\u010cetvrtak\", \"Petak\", \"Subota\" ],\n\tdayNamesShort: [ \"Ned\", \"Pon\", \"Uto\", \"Sri\", \"\u010cet\", \"Pet\", \"Sub\" ],\n\tdayNamesMin: [ \"Ne\", \"Po\", \"Ut\", \"Sr\", \"\u010ce\", \"Pe\", \"Su\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.bs );\n\nreturn datepicker.regional.bs;\n\n} );\n","jquery/ui-modules/i18n/datepicker-en-NZ.js":"/* English/New Zealand initialisation for the jQuery UI date picker plugin. */\n/* Based on the en-GB initialisation. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"en-NZ\" ] = {\n\tcloseText: \"Done\",\n\tprevText: \"Prev\",\n\tnextText: \"Next\",\n\tcurrentText: \"Today\",\n\tmonthNames: [ \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n\t\"July\", \"August\", \"September\", \"October\", \"November\", \"December\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ],\n\tdayNamesShort: [ \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\" ],\n\tdayNamesMin: [ \"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional[ \"en-NZ\" ] );\n\nreturn datepicker.regional[ \"en-NZ\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-ro.js":"/* Romanian initialisation for the jQuery UI date picker plugin.\n *\n * Written by Edmond L. ([email protected])\n * and Ionut G. Stan ([email protected])\n */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ro = {\n\tcloseText: \"\u00cenchide\",\n\tprevText: \"&#xAB; Luna precedent\u0103\",\n\tnextText: \"Luna urm\u0103toare &#xBB;\",\n\tcurrentText: \"Azi\",\n\tmonthNames: [ \"Ianuarie\", \"Februarie\", \"Martie\", \"Aprilie\", \"Mai\", \"Iunie\",\n\t\"Iulie\", \"August\", \"Septembrie\", \"Octombrie\", \"Noiembrie\", \"Decembrie\" ],\n\tmonthNamesShort: [ \"Ian\", \"Feb\", \"Mar\", \"Apr\", \"Mai\", \"Iun\",\n\t\"Iul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Duminic\u0103\", \"Luni\", \"Mar\u0163i\", \"Miercuri\", \"Joi\", \"Vineri\", \"S\u00e2mb\u0103t\u0103\" ],\n\tdayNamesShort: [ \"Dum\", \"Lun\", \"Mar\", \"Mie\", \"Joi\", \"Vin\", \"S\u00e2m\" ],\n\tdayNamesMin: [ \"Du\", \"Lu\", \"Ma\", \"Mi\", \"Jo\", \"Vi\", \"S\u00e2\" ],\n\tweekHeader: \"S\u0103pt\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.ro );\n\nreturn datepicker.regional.ro;\n\n} );\n","jquery/ui-modules/i18n/datepicker-en-AU.js":"/* English/Australia initialisation for the jQuery UI date picker plugin. */\n/* Based on the en-GB initialisation. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"en-AU\" ] = {\n\tcloseText: \"Done\",\n\tprevText: \"Prev\",\n\tnextText: \"Next\",\n\tcurrentText: \"Today\",\n\tmonthNames: [ \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n\t\"July\", \"August\", \"September\", \"October\", \"November\", \"December\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ],\n\tdayNamesShort: [ \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\" ],\n\tdayNamesMin: [ \"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional[ \"en-AU\" ] );\n\nreturn datepicker.regional[ \"en-AU\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-zh-TW.js":"/* Chinese initialisation for the jQuery UI date picker plugin. */\n/* Written by Ressol ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"zh-TW\" ] = {\n\tcloseText: \"\u95dc\u9589\",\n\tprevText: \"&#x3C;\u4e0a\u500b\u6708\",\n\tnextText: \"\u4e0b\u500b\u6708&#x3E;\",\n\tcurrentText: \"\u4eca\u5929\",\n\tmonthNames: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tmonthNamesShort: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tdayNames: [ \"\u661f\u671f\u65e5\", \"\u661f\u671f\u4e00\", \"\u661f\u671f\u4e8c\", \"\u661f\u671f\u4e09\", \"\u661f\u671f\u56db\", \"\u661f\u671f\u4e94\", \"\u661f\u671f\u516d\" ],\n\tdayNamesShort: [ \"\u9031\u65e5\", \"\u9031\u4e00\", \"\u9031\u4e8c\", \"\u9031\u4e09\", \"\u9031\u56db\", \"\u9031\u4e94\", \"\u9031\u516d\" ],\n\tdayNamesMin: [ \"\u65e5\", \"\u4e00\", \"\u4e8c\", \"\u4e09\", \"\u56db\", \"\u4e94\", \"\u516d\" ],\n\tweekHeader: \"\u9031\",\n\tdateFormat: \"yy/mm/dd\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: true,\n\tyearSuffix: \"\u5e74\" };\ndatepicker.setDefaults( datepicker.regional[ \"zh-TW\" ] );\n\nreturn datepicker.regional[ \"zh-TW\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-ja.js":"/* Japanese initialisation for the jQuery UI date picker plugin. */\n/* Written by Kentaro SATO ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ja = {\n\tcloseText: \"\u9589\u3058\u308b\",\n\tprevText: \"&#x3C;\u524d\",\n\tnextText: \"\u6b21&#x3E;\",\n\tcurrentText: \"\u4eca\u65e5\",\n\tmonthNames: [ \"1\u6708\", \"2\u6708\", \"3\u6708\", \"4\u6708\", \"5\u6708\", \"6\u6708\",\n\t\"7\u6708\", \"8\u6708\", \"9\u6708\", \"10\u6708\", \"11\u6708\", \"12\u6708\" ],\n\tmonthNamesShort: [ \"1\u6708\", \"2\u6708\", \"3\u6708\", \"4\u6708\", \"5\u6708\", \"6\u6708\",\n\t\"7\u6708\", \"8\u6708\", \"9\u6708\", \"10\u6708\", \"11\u6708\", \"12\u6708\" ],\n\tdayNames: [ \"\u65e5\u66dc\u65e5\", \"\u6708\u66dc\u65e5\", \"\u706b\u66dc\u65e5\", \"\u6c34\u66dc\u65e5\", \"\u6728\u66dc\u65e5\", \"\u91d1\u66dc\u65e5\", \"\u571f\u66dc\u65e5\" ],\n\tdayNamesShort: [ \"\u65e5\", \"\u6708\", \"\u706b\", \"\u6c34\", \"\u6728\", \"\u91d1\", \"\u571f\" ],\n\tdayNamesMin: [ \"\u65e5\", \"\u6708\", \"\u706b\", \"\u6c34\", \"\u6728\", \"\u91d1\", \"\u571f\" ],\n\tweekHeader: \"\u9031\",\n\tdateFormat: \"yy/mm/dd\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: true,\n\tyearSuffix: \"\u5e74\" };\ndatepicker.setDefaults( datepicker.regional.ja );\n\nreturn datepicker.regional.ja;\n\n} );\n","jquery/ui-modules/i18n/datepicker-zh-HK.js":"/* Chinese initialisation for the jQuery UI date picker plugin. */\n/* Written by SCCY ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"zh-HK\" ] = {\n\tcloseText: \"\u95dc\u9589\",\n\tprevText: \"&#x3C;\u4e0a\u6708\",\n\tnextText: \"\u4e0b\u6708&#x3E;\",\n\tcurrentText: \"\u4eca\u5929\",\n\tmonthNames: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tmonthNamesShort: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tdayNames: [ \"\u661f\u671f\u65e5\", \"\u661f\u671f\u4e00\", \"\u661f\u671f\u4e8c\", \"\u661f\u671f\u4e09\", \"\u661f\u671f\u56db\", \"\u661f\u671f\u4e94\", \"\u661f\u671f\u516d\" ],\n\tdayNamesShort: [ \"\u5468\u65e5\", \"\u5468\u4e00\", \"\u5468\u4e8c\", \"\u5468\u4e09\", \"\u5468\u56db\", \"\u5468\u4e94\", \"\u5468\u516d\" ],\n\tdayNamesMin: [ \"\u65e5\", \"\u4e00\", \"\u4e8c\", \"\u4e09\", \"\u56db\", \"\u4e94\", \"\u516d\" ],\n\tweekHeader: \"\u5468\",\n\tdateFormat: \"dd-mm-yy\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: true,\n\tyearSuffix: \"\u5e74\" };\ndatepicker.setDefaults( datepicker.regional[ \"zh-HK\" ] );\n\nreturn datepicker.regional[ \"zh-HK\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-ru.js":"/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Andrew Stromnov ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ru = {\n\tcloseText: \"\u0417\u0430\u043a\u0440\u044b\u0442\u044c\",\n\tprevText: \"&#x3C;\u041f\u0440\u0435\u0434\",\n\tnextText: \"\u0421\u043b\u0435\u0434&#x3E;\",\n\tcurrentText: \"\u0421\u0435\u0433\u043e\u0434\u043d\u044f\",\n\tmonthNames: [ \"\u042f\u043d\u0432\u0430\u0440\u044c\", \"\u0424\u0435\u0432\u0440\u0430\u043b\u044c\", \"\u041c\u0430\u0440\u0442\", \"\u0410\u043f\u0440\u0435\u043b\u044c\", \"\u041c\u0430\u0439\", \"\u0418\u044e\u043d\u044c\",\n\t\"\u0418\u044e\u043b\u044c\", \"\u0410\u0432\u0433\u0443\u0441\u0442\", \"\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c\", \"\u041e\u043a\u0442\u044f\u0431\u0440\u044c\", \"\u041d\u043e\u044f\u0431\u0440\u044c\", \"\u0414\u0435\u043a\u0430\u0431\u0440\u044c\" ],\n\tmonthNamesShort: [ \"\u042f\u043d\u0432\", \"\u0424\u0435\u0432\", \"\u041c\u0430\u0440\", \"\u0410\u043f\u0440\", \"\u041c\u0430\u0439\", \"\u0418\u044e\u043d\",\n\t\"\u0418\u044e\u043b\", \"\u0410\u0432\u0433\", \"\u0421\u0435\u043d\", \"\u041e\u043a\u0442\", \"\u041d\u043e\u044f\", \"\u0414\u0435\u043a\" ],\n\tdayNames: [ \"\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435\", \"\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a\", \"\u0432\u0442\u043e\u0440\u043d\u0438\u043a\", \"\u0441\u0440\u0435\u0434\u0430\", \"\u0447\u0435\u0442\u0432\u0435\u0440\u0433\", \"\u043f\u044f\u0442\u043d\u0438\u0446\u0430\", \"\u0441\u0443\u0431\u0431\u043e\u0442\u0430\" ],\n\tdayNamesShort: [ \"\u0432\u0441\u043a\", \"\u043f\u043d\u0434\", \"\u0432\u0442\u0440\", \"\u0441\u0440\u0434\", \"\u0447\u0442\u0432\", \"\u043f\u0442\u043d\", \"\u0441\u0431\u0442\" ],\n\tdayNamesMin: [ \"\u0412\u0441\", \"\u041f\u043d\", \"\u0412\u0442\", \"\u0421\u0440\", \"\u0427\u0442\", \"\u041f\u0442\", \"\u0421\u0431\" ],\n\tweekHeader: \"\u041d\u0435\u0434\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.ru );\n\nreturn datepicker.regional.ru;\n\n} );\n","jquery/ui-modules/i18n/datepicker-tj.js":"/* Tajiki (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Abdurahmon Saidov ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.tj = {\n\tcloseText: \"\u0418\u0434\u043e\u043c\u0430\",\n\tprevText: \"&#x3c;\u049a\u0430\u0444\u043e\",\n\tnextText: \"\u041f\u0435\u0448&#x3e;\",\n\tcurrentText: \"\u0418\u043c\u0440\u04ef\u0437\",\n\tmonthNames: [ \"\u042f\u043d\u0432\u0430\u0440\", \"\u0424\u0435\u0432\u0440\u0430\u043b\", \"\u041c\u0430\u0440\u0442\", \"\u0410\u043f\u0440\u0435\u043b\", \"\u041c\u0430\u0439\", \"\u0418\u044e\u043d\",\n\t\"\u0418\u044e\u043b\", \"\u0410\u0432\u0433\u0443\u0441\u0442\", \"\u0421\u0435\u043d\u0442\u044f\u0431\u0440\", \"\u041e\u043a\u0442\u044f\u0431\u0440\", \"\u041d\u043e\u044f\u0431\u0440\", \"\u0414\u0435\u043a\u0430\u0431\u0440\" ],\n\tmonthNamesShort: [ \"\u042f\u043d\u0432\", \"\u0424\u0435\u0432\", \"\u041c\u0430\u0440\", \"\u0410\u043f\u0440\", \"\u041c\u0430\u0439\", \"\u0418\u044e\u043d\",\n\t\"\u0418\u044e\u043b\", \"\u0410\u0432\u0433\", \"\u0421\u0435\u043d\", \"\u041e\u043a\u0442\", \"\u041d\u043e\u044f\", \"\u0414\u0435\u043a\" ],\n\tdayNames: [ \"\u044f\u043a\u0448\u0430\u043d\u0431\u0435\", \"\u0434\u0443\u0448\u0430\u043d\u0431\u0435\", \"\u0441\u0435\u0448\u0430\u043d\u0431\u0435\", \"\u0447\u043e\u0440\u0448\u0430\u043d\u0431\u0435\", \"\u043f\u0430\u043d\u04b7\u0448\u0430\u043d\u0431\u0435\", \"\u04b7\u0443\u043c\u044a\u0430\", \"\u0448\u0430\u043d\u0431\u0435\" ],\n\tdayNamesShort: [ \"\u044f\u043a\u0448\", \"\u0434\u0443\u0448\", \"\u0441\u0435\u0448\", \"\u0447\u043e\u0440\", \"\u043f\u0430\u043d\", \"\u04b7\u0443\u043c\", \"\u0448\u0430\u043d\" ],\n\tdayNamesMin: [ \"\u042f\u043a\", \"\u0414\u0448\", \"\u0421\u0448\", \"\u0427\u0448\", \"\u041f\u0448\", \"\u04b6\u043c\", \"\u0428\u043d\" ],\n\tweekHeader: \"\u0425\u0444\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.tj );\n\nreturn datepicker.regional.tj;\n\n} );\n","jquery/ui-modules/i18n/datepicker-be.js":"/* Belarusian initialisation for the jQuery UI date picker plugin. */\n/* Written by Pavel Selitskas <[email protected]> */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.be = {\n\tcloseText: \"\u0417\u0430\u0447\u044b\u043d\u0456\u0446\u044c\",\n\tprevText: \"&larr;\u041f\u0430\u043f\u044f\u0440.\",\n\tnextText: \"\u041d\u0430\u0441\u0442.&rarr;\",\n\tcurrentText: \"\u0421\u0451\u043d\u044c\u043d\u044f\",\n\tmonthNames: [ \"\u0421\u0442\u0443\u0434\u0437\u0435\u043d\u044c\", \"\u041b\u044e\u0442\u044b\", \"\u0421\u0430\u043a\u0430\u0432\u0456\u043a\", \"\u041a\u0440\u0430\u0441\u0430\u0432\u0456\u043a\", \"\u0422\u0440\u0430\u0432\u0435\u043d\u044c\", \"\u0427\u044d\u0440\u0432\u0435\u043d\u044c\",\n\t\"\u041b\u0456\u043f\u0435\u043d\u044c\", \"\u0416\u043d\u0456\u0432\u0435\u043d\u044c\", \"\u0412\u0435\u0440\u0430\u0441\u0435\u043d\u044c\", \"\u041a\u0430\u0441\u0442\u0440\u044b\u0447\u043d\u0456\u043a\", \"\u041b\u0456\u0441\u0442\u0430\u043f\u0430\u0434\", \"\u0421\u044c\u043d\u0435\u0436\u0430\u043d\u044c\" ],\n\tmonthNamesShort: [ \"\u0421\u0442\u0443\", \"\u041b\u044e\u0442\", \"\u0421\u0430\u043a\", \"\u041a\u0440\u0430\", \"\u0422\u0440\u0430\", \"\u0427\u044d\u0440\",\n\t\"\u041b\u0456\u043f\", \"\u0416\u043d\u0456\", \"\u0412\u0435\u0440\", \"\u041a\u0430\u0441\", \"\u041b\u0456\u0441\", \"\u0421\u044c\u043d\" ],\n\tdayNames: [ \"\u043d\u044f\u0434\u0437\u0435\u043b\u044f\", \"\u043f\u0430\u043d\u044f\u0434\u0437\u0435\u043b\u0430\u043a\", \"\u0430\u045e\u0442\u043e\u0440\u0430\u043a\", \"\u0441\u0435\u0440\u0430\u0434\u0430\", \"\u0447\u0430\u0446\u044c\u0432\u0435\u0440\", \"\u043f\u044f\u0442\u043d\u0456\u0446\u0430\", \"\u0441\u0443\u0431\u043e\u0442\u0430\" ],\n\tdayNamesShort: [ \"\u043d\u0434\u0437\", \"\u043f\u043d\u0434\", \"\u0430\u045e\u0442\", \"\u0441\u0440\u0434\", \"\u0447\u0446\u0432\", \"\u043f\u0442\u043d\", \"\u0441\u0431\u0442\" ],\n\tdayNamesMin: [ \"\u041d\u0434\", \"\u041f\u043d\", \"\u0410\u045e\", \"\u0421\u0440\", \"\u0427\u0446\", \"\u041f\u0442\", \"\u0421\u0431\" ],\n\tweekHeader: \"\u0422\u0434\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.be );\n\nreturn datepicker.regional.be;\n\n} );\n","jquery/ui-modules/i18n/datepicker-sl.js":"/* Slovenian initialisation for the jQuery UI date picker plugin. */\n/* Written by Jaka Jancar ([email protected]). */\n/* c = \u010d, s = \u0161 z = \u017e C = \u010c S = \u0160 Z = \u017d */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.sl = {\n\tcloseText: \"Zapri\",\n\tprevText: \"&#x3C;Prej\u0161nji\",\n\tnextText: \"Naslednji&#x3E;\",\n\tcurrentText: \"Trenutni\",\n\tmonthNames: [ \"Januar\", \"Februar\", \"Marec\", \"April\", \"Maj\", \"Junij\",\n\t\"Julij\", \"Avgust\", \"September\", \"Oktober\", \"November\", \"December\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\",\n\t\"Jul\", \"Avg\", \"Sep\", \"Okt\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"Nedelja\", \"Ponedeljek\", \"Torek\", \"Sreda\", \"\u010cetrtek\", \"Petek\", \"Sobota\" ],\n\tdayNamesShort: [ \"Ned\", \"Pon\", \"Tor\", \"Sre\", \"\u010cet\", \"Pet\", \"Sob\" ],\n\tdayNamesMin: [ \"Ne\", \"Po\", \"To\", \"Sr\", \"\u010ce\", \"Pe\", \"So\" ],\n\tweekHeader: \"Teden\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.sl );\n\nreturn datepicker.regional.sl;\n\n} );\n","jquery/ui-modules/i18n/datepicker-ml.js":"/* Malayalam (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Saji Nediyanchath ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ml = {\n\tcloseText: \"\u0d36\u0d30\u0d3f\",\n\tprevText: \"\u0d2e\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d4d\u0d24\u0d46\",\n\tnextText: \"\u0d05\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d24\u0d4d \",\n\tcurrentText: \"\u0d07\u0d28\u0d4d\u0d28\u0d4d\",\n\tmonthNames: [ \"\u0d1c\u0d28\u0d41\u0d35\u0d30\u0d3f\", \"\u0d2b\u0d46\u0d2c\u0d4d\u0d30\u0d41\u0d35\u0d30\u0d3f\", \"\u0d2e\u0d3e\u0d30\u0d4d\u200d\u0d1a\u0d4d\u0d1a\u0d4d\", \"\u0d0f\u0d2a\u0d4d\u0d30\u0d3f\u0d32\u0d4d\u200d\", \"\u0d2e\u0d47\u0d2f\u0d4d\", \"\u0d1c\u0d42\u0d23\u0d4d\u200d\",\n\t\"\u0d1c\u0d42\u0d32\u0d48\", \"\u0d06\u0d17\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d\", \"\u0d38\u0d46\u0d2a\u0d4d\u0d31\u0d4d\u0d31\u0d02\u0d2c\u0d30\u0d4d\u200d\", \"\u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d30\u0d4d\u200d\", \"\u0d28\u0d35\u0d02\u0d2c\u0d30\u0d4d\u200d\", \"\u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d30\u0d4d\u200d\" ],\n\tmonthNamesShort: [ \"\u0d1c\u0d28\u0d41\", \"\u0d2b\u0d46\u0d2c\u0d4d\", \"\u0d2e\u0d3e\u0d30\u0d4d\u200d\", \"\u0d0f\u0d2a\u0d4d\u0d30\u0d3f\", \"\u0d2e\u0d47\u0d2f\u0d4d\", \"\u0d1c\u0d42\u0d23\u0d4d\u200d\",\n\t\"\u0d1c\u0d42\u0d32\u0d3e\", \"\u0d06\u0d17\", \"\u0d38\u0d46\u0d2a\u0d4d\", \"\u0d12\u0d15\u0d4d\u0d1f\u0d4b\", \"\u0d28\u0d35\u0d02\", \"\u0d21\u0d3f\u0d38\" ],\n\tdayNames: [ \"\u0d1e\u0d3e\u0d2f\u0d30\u0d4d\u200d\", \"\u0d24\u0d3f\u0d19\u0d4d\u0d15\u0d33\u0d4d\u200d\", \"\u0d1a\u0d4a\u0d35\u0d4d\u0d35\", \"\u0d2c\u0d41\u0d27\u0d28\u0d4d\u200d\", \"\u0d35\u0d4d\u0d2f\u0d3e\u0d34\u0d02\", \"\u0d35\u0d46\u0d33\u0d4d\u0d33\u0d3f\", \"\u0d36\u0d28\u0d3f\" ],\n\tdayNamesShort: [ \"\u0d1e\u0d3e\u0d2f\", \"\u0d24\u0d3f\u0d19\u0d4d\u0d15\", \"\u0d1a\u0d4a\u0d35\u0d4d\u0d35\", \"\u0d2c\u0d41\u0d27\", \"\u0d35\u0d4d\u0d2f\u0d3e\u0d34\u0d02\", \"\u0d35\u0d46\u0d33\u0d4d\u0d33\u0d3f\", \"\u0d36\u0d28\u0d3f\" ],\n\tdayNamesMin: [ \"\u0d1e\u0d3e\", \"\u0d24\u0d3f\", \"\u0d1a\u0d4a\", \"\u0d2c\u0d41\", \"\u0d35\u0d4d\u0d2f\u0d3e\", \"\u0d35\u0d46\", \"\u0d36\" ],\n\tweekHeader: \"\u0d06\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.ml );\n\nreturn datepicker.regional.ml;\n\n} );\n","jquery/ui-modules/i18n/datepicker-ar.js":"/* Arabic Translation for jQuery UI date picker plugin. */\n/* Used in most of Arab countries, primarily in Bahrain, */\n/* Kuwait, Oman, Qatar, Saudi Arabia and the United Arab Emirates, Egypt, Sudan and Yemen. */\n/* Written by Mohammed Alshehri -- [email protected] */\n\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ar = {\n\tcloseText: \"\u0625\u063a\u0644\u0627\u0642\",\n\tprevText: \"&#x3C;\u0627\u0644\u0633\u0627\u0628\u0642\",\n\tnextText: \"\u0627\u0644\u062a\u0627\u0644\u064a&#x3E;\",\n\tcurrentText: \"\u0627\u0644\u064a\u0648\u0645\",\n\tmonthNames: [ \"\u064a\u0646\u0627\u064a\u0631\", \"\u0641\u0628\u0631\u0627\u064a\u0631\", \"\u0645\u0627\u0631\u0633\", \"\u0623\u0628\u0631\u064a\u0644\", \"\u0645\u0627\u064a\u0648\", \"\u064a\u0648\u0646\u064a\u0648\",\n\t\"\u064a\u0648\u0644\u064a\u0648\", \"\u0623\u063a\u0633\u0637\u0633\", \"\u0633\u0628\u062a\u0645\u0628\u0631\", \"\u0623\u0643\u062a\u0648\u0628\u0631\", \"\u0646\u0648\u0641\u0645\u0628\u0631\", \"\u062f\u064a\u0633\u0645\u0628\u0631\" ],\n\tmonthNamesShort: [ \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\" ],\n\tdayNames: [ \"\u0627\u0644\u0623\u062d\u062f\", \"\u0627\u0644\u0627\u062b\u0646\u064a\u0646\", \"\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621\", \"\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621\", \"\u0627\u0644\u062e\u0645\u064a\u0633\", \"\u0627\u0644\u062c\u0645\u0639\u0629\", \"\u0627\u0644\u0633\u0628\u062a\" ],\n\tdayNamesShort: [ \"\u0623\u062d\u062f\", \"\u0627\u062b\u0646\u064a\u0646\", \"\u062b\u0644\u0627\u062b\u0627\u0621\", \"\u0623\u0631\u0628\u0639\u0627\u0621\", \"\u062e\u0645\u064a\u0633\", \"\u062c\u0645\u0639\u0629\", \"\u0633\u0628\u062a\" ],\n\tdayNamesMin: [ \"\u062d\", \"\u0646\", \"\u062b\", \"\u0631\", \"\u062e\", \"\u062c\", \"\u0633\" ],\n\tweekHeader: \"\u0623\u0633\u0628\u0648\u0639\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 0,\n\t\tisRTL: true,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.ar );\n\nreturn datepicker.regional.ar;\n\n} );\n","jquery/ui-modules/i18n/datepicker-lv.js":"/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* @author Arturas Paleicikas <[email protected]> */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.lv = {\n\tcloseText: \"Aizv\u0113rt\",\n\tprevText: \"Iepr.\",\n\tnextText: \"N\u0101k.\",\n\tcurrentText: \"\u0160odien\",\n\tmonthNames: [ \"Janv\u0101ris\", \"Febru\u0101ris\", \"Marts\", \"Apr\u012blis\", \"Maijs\", \"J\u016bnijs\",\n\t\"J\u016blijs\", \"Augusts\", \"Septembris\", \"Oktobris\", \"Novembris\", \"Decembris\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Mai\", \"J\u016bn\",\n\t\"J\u016bl\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\" ],\n\tdayNames: [\n\t\t\"sv\u0113tdiena\",\n\t\t\"pirmdiena\",\n\t\t\"otrdiena\",\n\t\t\"tre\u0161diena\",\n\t\t\"ceturtdiena\",\n\t\t\"piektdiena\",\n\t\t\"sestdiena\"\n\t],\n\tdayNamesShort: [ \"svt\", \"prm\", \"otr\", \"tre\", \"ctr\", \"pkt\", \"sst\" ],\n\tdayNamesMin: [ \"Sv\", \"Pr\", \"Ot\", \"Tr\", \"Ct\", \"Pk\", \"Ss\" ],\n\tweekHeader: \"Ned.\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.lv );\n\nreturn datepicker.regional.lv;\n\n} );\n","jquery/ui-modules/i18n/datepicker-sk.js":"/* Slovak initialisation for the jQuery UI date picker plugin. */\n/* Written by Vojtech Rinik ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.sk = {\n\tcloseText: \"Zavrie\u0165\",\n\tprevText: \"&#x3C;Predch\u00e1dzaj\u00faci\",\n\tnextText: \"Nasleduj\u00faci&#x3E;\",\n\tcurrentText: \"Dnes\",\n\tmonthNames: [ \"janu\u00e1r\", \"febru\u00e1r\", \"marec\", \"apr\u00edl\", \"m\u00e1j\", \"j\u00fan\",\n\t\"j\u00fal\", \"august\", \"september\", \"okt\u00f3ber\", \"november\", \"december\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"M\u00e1j\", \"J\u00fan\",\n\t\"J\u00fal\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\" ],\n\tdayNames: [ \"nede\u013ea\", \"pondelok\", \"utorok\", \"streda\", \"\u0161tvrtok\", \"piatok\", \"sobota\" ],\n\tdayNamesShort: [ \"Ned\", \"Pon\", \"Uto\", \"Str\", \"\u0160tv\", \"Pia\", \"Sob\" ],\n\tdayNamesMin: [ \"Ne\", \"Po\", \"Ut\", \"St\", \"\u0160t\", \"Pia\", \"So\" ],\n\tweekHeader: \"Ty\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.sk );\n\nreturn datepicker.regional.sk;\n\n} );\n","jquery/ui-modules/i18n/datepicker-cs.js":"/* Czech initialisation for the jQuery UI date picker plugin. */\n/* Written by Tomas Muller ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.cs = {\n\tcloseText: \"Zav\u0159\u00edt\",\n\tprevText: \"&#x3C;D\u0159\u00edve\",\n\tnextText: \"Pozd\u011bji&#x3E;\",\n\tcurrentText: \"Nyn\u00ed\",\n\tmonthNames: [ \"leden\", \"\u00fanor\", \"b\u0159ezen\", \"duben\", \"kv\u011bten\", \"\u010derven\",\n\t\"\u010dervenec\", \"srpen\", \"z\u00e1\u0159\u00ed\", \"\u0159\u00edjen\", \"listopad\", \"prosinec\" ],\n\tmonthNamesShort: [ \"led\", \"\u00fano\", \"b\u0159e\", \"dub\", \"kv\u011b\", \"\u010der\",\n\t\"\u010dvc\", \"srp\", \"z\u00e1\u0159\", \"\u0159\u00edj\", \"lis\", \"pro\" ],\n\tdayNames: [ \"ned\u011ble\", \"pond\u011bl\u00ed\", \"\u00fater\u00fd\", \"st\u0159eda\", \"\u010dtvrtek\", \"p\u00e1tek\", \"sobota\" ],\n\tdayNamesShort: [ \"ne\", \"po\", \"\u00fat\", \"st\", \"\u010dt\", \"p\u00e1\", \"so\" ],\n\tdayNamesMin: [ \"ne\", \"po\", \"\u00fat\", \"st\", \"\u010dt\", \"p\u00e1\", \"so\" ],\n\tweekHeader: \"T\u00fdd\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.cs );\n\nreturn datepicker.regional.cs;\n\n} );\n","jquery/ui-modules/i18n/datepicker-fa.js":"/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */\n/* Javad Mowlanezhad -- [email protected] */\n/* Jalali calendar should supported soon! (Its implemented but I have to test it) */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.fa = {\n\tcloseText: \"\u0628\u0633\u062a\u0646\",\n\tprevText: \"&#x3C;\u0642\u0628\u0644\u06cc\",\n\tnextText: \"\u0628\u0639\u062f\u06cc&#x3E;\",\n\tcurrentText: \"\u0627\u0645\u0631\u0648\u0632\",\n\tmonthNames: [\n\t\t\"\u0698\u0627\u0646\u0648\u06cc\u0647\",\n\t\t\"\u0641\u0648\u0631\u06cc\u0647\",\n\t\t\"\u0645\u0627\u0631\u0633\",\n\t\t\"\u0622\u0648\u0631\u06cc\u0644\",\n\t\t\"\u0645\u0647\",\n\t\t\"\u0698\u0648\u0626\u0646\",\n\t\t\"\u0698\u0648\u0626\u06cc\u0647\",\n\t\t\"\u0627\u0648\u062a\",\n\t\t\"\u0633\u067e\u062a\u0627\u0645\u0628\u0631\",\n\t\t\"\u0627\u06a9\u062a\u0628\u0631\",\n\t\t\"\u0646\u0648\u0627\u0645\u0628\u0631\",\n\t\t\"\u062f\u0633\u0627\u0645\u0628\u0631\"\n\t],\n\tmonthNamesShort: [ \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\" ],\n\tdayNames: [\n\t\t\"\u064a\u06a9\u0634\u0646\u0628\u0647\",\n\t\t\"\u062f\u0648\u0634\u0646\u0628\u0647\",\n\t\t\"\u0633\u0647\u200c\u0634\u0646\u0628\u0647\",\n\t\t\"\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647\",\n\t\t\"\u067e\u0646\u062c\u0634\u0646\u0628\u0647\",\n\t\t\"\u062c\u0645\u0639\u0647\",\n\t\t\"\u0634\u0646\u0628\u0647\"\n\t],\n\tdayNamesShort: [\n\t\t\"\u06cc\",\n\t\t\"\u062f\",\n\t\t\"\u0633\",\n\t\t\"\u0686\",\n\t\t\"\u067e\",\n\t\t\"\u062c\",\n\t\t\"\u0634\"\n\t],\n\tdayNamesMin: [\n\t\t\"\u06cc\",\n\t\t\"\u062f\",\n\t\t\"\u0633\",\n\t\t\"\u0686\",\n\t\t\"\u067e\",\n\t\t\"\u062c\",\n\t\t\"\u0634\"\n\t],\n\tweekHeader: \"\u0647\u0641\",\n\tdateFormat: \"yy/mm/dd\",\n\tfirstDay: 6,\n\tisRTL: true,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.fa );\n\nreturn datepicker.regional.fa;\n\n} );\n","jquery/ui-modules/i18n/datepicker-cy-GB.js":"/* Welsh/UK initialisation for the jQuery UI date picker plugin. */\n/* Written by William Griffiths. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"cy-GB\" ] = {\n\tcloseText: \"Done\",\n\tprevText: \"Prev\",\n\tnextText: \"Next\",\n\tcurrentText: \"Today\",\n\tmonthNames: [ \"Ionawr\", \"Chwefror\", \"Mawrth\", \"Ebrill\", \"Mai\", \"Mehefin\",\n\t\"Gorffennaf\", \"Awst\", \"Medi\", \"Hydref\", \"Tachwedd\", \"Rhagfyr\" ],\n\tmonthNamesShort: [ \"Ion\", \"Chw\", \"Maw\", \"Ebr\", \"Mai\", \"Meh\",\n\t\"Gor\", \"Aws\", \"Med\", \"Hyd\", \"Tac\", \"Rha\" ],\n\tdayNames: [\n\t\t\"Dydd Sul\",\n\t\t\"Dydd Llun\",\n\t\t\"Dydd Mawrth\",\n\t\t\"Dydd Mercher\",\n\t\t\"Dydd Iau\",\n\t\t\"Dydd Gwener\",\n\t\t\"Dydd Sadwrn\"\n\t],\n\tdayNamesShort: [ \"Sul\", \"Llu\", \"Maw\", \"Mer\", \"Iau\", \"Gwe\", \"Sad\" ],\n\tdayNamesMin: [ \"Su\", \"Ll\", \"Ma\", \"Me\", \"Ia\", \"Gw\", \"Sa\" ],\n\tweekHeader: \"Wy\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional[ \"cy-GB\" ] );\n\nreturn datepicker.regional[ \"cy-GB\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-kk.js":"/* Kazakh (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Dmitriy Karasyov ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.kk = {\n\tcloseText: \"\u0416\u0430\u0431\u0443\",\n\tprevText: \"&#x3C;\u0410\u043b\u0434\u044b\u04a3\u0493\u044b\",\n\tnextText: \"\u041a\u0435\u043b\u0435\u0441\u0456&#x3E;\",\n\tcurrentText: \"\u0411\u04af\u0433\u0456\u043d\",\n\tmonthNames: [ \"\u049a\u0430\u04a3\u0442\u0430\u0440\", \"\u0410\u049b\u043f\u0430\u043d\", \"\u041d\u0430\u0443\u0440\u044b\u0437\", \"\u0421\u04d9\u0443\u0456\u0440\", \"\u041c\u0430\u043c\u044b\u0440\", \"\u041c\u0430\u0443\u0441\u044b\u043c\",\n\t\"\u0428\u0456\u043b\u0434\u0435\", \"\u0422\u0430\u043c\u044b\u0437\", \"\u049a\u044b\u0440\u043a\u04af\u0439\u0435\u043a\", \"\u049a\u0430\u0437\u0430\u043d\", \"\u049a\u0430\u0440\u0430\u0448\u0430\", \"\u0416\u0435\u043b\u0442\u043e\u049b\u0441\u0430\u043d\" ],\n\tmonthNamesShort: [ \"\u049a\u0430\u04a3\", \"\u0410\u049b\u043f\", \"\u041d\u0430\u0443\", \"\u0421\u04d9\u0443\", \"\u041c\u0430\u043c\", \"\u041c\u0430\u0443\",\n\t\"\u0428\u0456\u043b\", \"\u0422\u0430\u043c\", \"\u049a\u044b\u0440\", \"\u049a\u0430\u0437\", \"\u049a\u0430\u0440\", \"\u0416\u0435\u043b\" ],\n\tdayNames: [ \"\u0416\u0435\u043a\u0441\u0435\u043d\u0431\u0456\", \"\u0414\u04af\u0439\u0441\u0435\u043d\u0431\u0456\", \"\u0421\u0435\u0439\u0441\u0435\u043d\u0431\u0456\", \"\u0421\u04d9\u0440\u0441\u0435\u043d\u0431\u0456\", \"\u0411\u0435\u0439\u0441\u0435\u043d\u0431\u0456\", \"\u0416\u04b1\u043c\u0430\", \"\u0421\u0435\u043d\u0431\u0456\" ],\n\tdayNamesShort: [ \"\u0436\u043a\u0441\", \"\u0434\u0441\u043d\", \"\u0441\u0441\u043d\", \"\u0441\u0440\u0441\", \"\u0431\u0441\u043d\", \"\u0436\u043c\u0430\", \"\u0441\u043d\u0431\" ],\n\tdayNamesMin: [ \"\u0416\u043a\", \"\u0414\u0441\", \"\u0421\u0441\", \"\u0421\u0440\", \"\u0411\u0441\", \"\u0416\u043c\", \"\u0421\u043d\" ],\n\tweekHeader: \"\u041d\u0435\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.kk );\n\nreturn datepicker.regional.kk;\n\n} );\n","jquery/ui-modules/i18n/datepicker-sq.js":"/* Albanian initialisation for the jQuery UI date picker plugin. */\n/* Written by Flakron Bytyqi ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.sq = {\n\tcloseText: \"mbylle\",\n\tprevText: \"&#x3C;mbrapa\",\n\tnextText: \"P\u00ebrpara&#x3E;\",\n\tcurrentText: \"sot\",\n\tmonthNames: [ \"Janar\", \"Shkurt\", \"Mars\", \"Prill\", \"Maj\", \"Qershor\",\n\t\"Korrik\", \"Gusht\", \"Shtator\", \"Tetor\", \"N\u00ebntor\", \"Dhjetor\" ],\n\tmonthNamesShort: [ \"Jan\", \"Shk\", \"Mar\", \"Pri\", \"Maj\", \"Qer\",\n\t\"Kor\", \"Gus\", \"Sht\", \"Tet\", \"N\u00ebn\", \"Dhj\" ],\n\tdayNames: [ \"E Diel\", \"E H\u00ebn\u00eb\", \"E Mart\u00eb\", \"E M\u00ebrkur\u00eb\", \"E Enjte\", \"E Premte\", \"E Shtune\" ],\n\tdayNamesShort: [ \"Di\", \"H\u00eb\", \"Ma\", \"M\u00eb\", \"En\", \"Pr\", \"Sh\" ],\n\tdayNamesMin: [ \"Di\", \"H\u00eb\", \"Ma\", \"M\u00eb\", \"En\", \"Pr\", \"Sh\" ],\n\tweekHeader: \"Ja\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.sq );\n\nreturn datepicker.regional.sq;\n\n} );\n","jquery/ui-modules/i18n/datepicker-nl.js":"/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Mathias Bynens <http://mathiasbynens.be/> */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.nl = {\n\tcloseText: \"Sluiten\",\n\tprevText: \"\u2190\",\n\tnextText: \"\u2192\",\n\tcurrentText: \"Vandaag\",\n\tmonthNames: [ \"januari\", \"februari\", \"maart\", \"april\", \"mei\", \"juni\",\n\t\"juli\", \"augustus\", \"september\", \"oktober\", \"november\", \"december\" ],\n\tmonthNamesShort: [ \"jan\", \"feb\", \"mrt\", \"apr\", \"mei\", \"jun\",\n\t\"jul\", \"aug\", \"sep\", \"okt\", \"nov\", \"dec\" ],\n\tdayNames: [ \"zondag\", \"maandag\", \"dinsdag\", \"woensdag\", \"donderdag\", \"vrijdag\", \"zaterdag\" ],\n\tdayNamesShort: [ \"zon\", \"maa\", \"din\", \"woe\", \"don\", \"vri\", \"zat\" ],\n\tdayNamesMin: [ \"zo\", \"ma\", \"di\", \"wo\", \"do\", \"vr\", \"za\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd-mm-yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.nl );\n\nreturn datepicker.regional.nl;\n\n} );\n","jquery/ui-modules/i18n/datepicker-km.js":"/* Khmer initialisation for the jQuery calendar extension. */\n/* Written by Chandara Om ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.km = {\n\tcloseText: \"\u1792\u17d2\u179c\u17be\u200b\u179a\u17bd\u1785\",\n\tprevText: \"\u1798\u17bb\u1793\",\n\tnextText: \"\u1794\u1793\u17d2\u1791\u17b6\u1794\u17cb\",\n\tcurrentText: \"\u1790\u17d2\u1784\u17c3\u200b\u1793\u17c1\u17c7\",\n\tmonthNames: [ \"\u1798\u1780\u179a\u17b6\", \"\u1780\u17bb\u1798\u17d2\u1797\u17c8\", \"\u1798\u17b8\u1793\u17b6\", \"\u1798\u17c1\u179f\u17b6\", \"\u17a7\u179f\u1797\u17b6\", \"\u1798\u17b7\u1790\u17bb\u1793\u17b6\",\n\t\"\u1780\u1780\u17d2\u1780\u178a\u17b6\", \"\u179f\u17b8\u17a0\u17b6\", \"\u1780\u1789\u17d2\u1789\u17b6\", \"\u178f\u17bb\u179b\u17b6\", \"\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6\", \"\u1792\u17d2\u1793\u17bc\" ],\n\tmonthNamesShort: [ \"\u1798\u1780\u179a\u17b6\", \"\u1780\u17bb\u1798\u17d2\u1797\u17c8\", \"\u1798\u17b8\u1793\u17b6\", \"\u1798\u17c1\u179f\u17b6\", \"\u17a7\u179f\u1797\u17b6\", \"\u1798\u17b7\u1790\u17bb\u1793\u17b6\",\n\t\"\u1780\u1780\u17d2\u1780\u178a\u17b6\", \"\u179f\u17b8\u17a0\u17b6\", \"\u1780\u1789\u17d2\u1789\u17b6\", \"\u178f\u17bb\u179b\u17b6\", \"\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6\", \"\u1792\u17d2\u1793\u17bc\" ],\n\tdayNames: [ \"\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799\", \"\u1785\u1793\u17d2\u1791\", \"\u17a2\u1784\u17d2\u1782\u17b6\u179a\", \"\u1796\u17bb\u1792\", \"\u1796\u17d2\u179a\u17a0\u179f\u17d2\u1794\u178f\u17b7\u17cd\", \"\u179f\u17bb\u1780\u17d2\u179a\", \"\u179f\u17c5\u179a\u17cd\" ],\n\tdayNamesShort: [ \"\u17a2\u17b6\", \"\u1785\", \"\u17a2\", \"\u1796\u17bb\", \"\u1796\u17d2\u179a\u17a0\", \"\u179f\u17bb\", \"\u179f\u17c5\" ],\n\tdayNamesMin: [ \"\u17a2\u17b6\", \"\u1785\", \"\u17a2\", \"\u1796\u17bb\", \"\u1796\u17d2\u179a\u17a0\", \"\u179f\u17bb\", \"\u179f\u17c5\" ],\n\tweekHeader: \"\u179f\u1794\u17d2\u178a\u17b6\u17a0\u17cd\",\n\tdateFormat: \"dd-mm-yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.km );\n\nreturn datepicker.regional.km;\n\n} );\n","jquery/ui-modules/i18n/datepicker-fr-CA.js":"/* Canadian-French initialisation for the jQuery UI date picker plugin. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"fr-CA\" ] = {\n\tcloseText: \"Fermer\",\n\tprevText: \"Pr\u00e9c\u00e9dent\",\n\tnextText: \"Suivant\",\n\tcurrentText: \"Aujourd'hui\",\n\tmonthNames: [ \"janvier\", \"f\u00e9vrier\", \"mars\", \"avril\", \"mai\", \"juin\",\n\t\t\"juillet\", \"ao\u00fbt\", \"septembre\", \"octobre\", \"novembre\", \"d\u00e9cembre\" ],\n\tmonthNamesShort: [ \"janv.\", \"f\u00e9vr.\", \"mars\", \"avril\", \"mai\", \"juin\",\n\t\t\"juil.\", \"ao\u00fbt\", \"sept.\", \"oct.\", \"nov.\", \"d\u00e9c.\" ],\n\tdayNames: [ \"dimanche\", \"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\" ],\n\tdayNamesShort: [ \"dim.\", \"lun.\", \"mar.\", \"mer.\", \"jeu.\", \"ven.\", \"sam.\" ],\n\tdayNamesMin: [ \"D\", \"L\", \"M\", \"M\", \"J\", \"V\", \"S\" ],\n\tweekHeader: \"Sem.\",\n\tdateFormat: \"yy-mm-dd\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\"\n};\ndatepicker.setDefaults( datepicker.regional[ \"fr-CA\" ] );\n\nreturn datepicker.regional[ \"fr-CA\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-de-AT.js":"/* German/Austrian initialisation for the jQuery UI date picker plugin. */\n/* Based on the de initialisation. */\n\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"de-AT\" ] = {\n\tcloseText: \"Schlie\u00dfen\",\n\tprevText: \"&#x3C;Zur\u00fcck\",\n\tnextText: \"Vor&#x3E;\",\n\tcurrentText: \"Heute\",\n\tmonthNames: [ \"J\u00e4nner\", \"Februar\", \"M\u00e4rz\", \"April\", \"Mai\", \"Juni\",\n\t\"Juli\", \"August\", \"September\", \"Oktober\", \"November\", \"Dezember\" ],\n\tmonthNamesShort: [ \"J\u00e4n\", \"Feb\", \"M\u00e4r\", \"Apr\", \"Mai\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dez\" ],\n\tdayNames: [ \"Sonntag\", \"Montag\", \"Dienstag\", \"Mittwoch\", \"Donnerstag\", \"Freitag\", \"Samstag\" ],\n\tdayNamesShort: [ \"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\" ],\n\tdayNamesMin: [ \"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\" ],\n\tweekHeader: \"KW\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional[ \"de-AT\" ] );\n\nreturn datepicker.regional[ \"de-AT\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-pt.js":"/* Portuguese initialisation for the jQuery UI date picker plugin. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.pt = {\n\tcloseText: \"Fechar\",\n\tprevText: \"Anterior\",\n\tnextText: \"Seguinte\",\n\tcurrentText: \"Hoje\",\n\tmonthNames: [ \"Janeiro\", \"Fevereiro\", \"Mar\u00e7o\", \"Abril\", \"Maio\", \"Junho\",\n\t\"Julho\", \"Agosto\", \"Setembro\", \"Outubro\", \"Novembro\", \"Dezembro\" ],\n\tmonthNamesShort: [ \"Jan\", \"Fev\", \"Mar\", \"Abr\", \"Mai\", \"Jun\",\n\t\"Jul\", \"Ago\", \"Set\", \"Out\", \"Nov\", \"Dez\" ],\n\tdayNames: [\n\t\t\"Domingo\",\n\t\t\"Segunda-feira\",\n\t\t\"Ter\u00e7a-feira\",\n\t\t\"Quarta-feira\",\n\t\t\"Quinta-feira\",\n\t\t\"Sexta-feira\",\n\t\t\"S\u00e1bado\"\n\t],\n\tdayNamesShort: [ \"Dom\", \"Seg\", \"Ter\", \"Qua\", \"Qui\", \"Sex\", \"S\u00e1b\" ],\n\tdayNamesMin: [ \"Dom\", \"Seg\", \"Ter\", \"Qua\", \"Qui\", \"Sex\", \"S\u00e1b\" ],\n\tweekHeader: \"Sem\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.pt );\n\nreturn datepicker.regional.pt;\n\n} );\n","jquery/ui-modules/i18n/datepicker-ko.js":"/* Korean initialisation for the jQuery calendar extension. */\n/* Written by DaeKwon Kang ([email protected]), Edited by Genie and Myeongjin Lee. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.ko = {\n\tcloseText: \"\ub2eb\uae30\",\n\tprevText: \"\uc774\uc804\ub2ec\",\n\tnextText: \"\ub2e4\uc74c\ub2ec\",\n\tcurrentText: \"\uc624\ub298\",\n\tmonthNames: [ \"1\uc6d4\", \"2\uc6d4\", \"3\uc6d4\", \"4\uc6d4\", \"5\uc6d4\", \"6\uc6d4\",\n\t\"7\uc6d4\", \"8\uc6d4\", \"9\uc6d4\", \"10\uc6d4\", \"11\uc6d4\", \"12\uc6d4\" ],\n\tmonthNamesShort: [ \"1\uc6d4\", \"2\uc6d4\", \"3\uc6d4\", \"4\uc6d4\", \"5\uc6d4\", \"6\uc6d4\",\n\t\"7\uc6d4\", \"8\uc6d4\", \"9\uc6d4\", \"10\uc6d4\", \"11\uc6d4\", \"12\uc6d4\" ],\n\tdayNames: [ \"\uc77c\uc694\uc77c\", \"\uc6d4\uc694\uc77c\", \"\ud654\uc694\uc77c\", \"\uc218\uc694\uc77c\", \"\ubaa9\uc694\uc77c\", \"\uae08\uc694\uc77c\", \"\ud1a0\uc694\uc77c\" ],\n\tdayNamesShort: [ \"\uc77c\", \"\uc6d4\", \"\ud654\", \"\uc218\", \"\ubaa9\", \"\uae08\", \"\ud1a0\" ],\n\tdayNamesMin: [ \"\uc77c\", \"\uc6d4\", \"\ud654\", \"\uc218\", \"\ubaa9\", \"\uae08\", \"\ud1a0\" ],\n\tweekHeader: \"\uc8fc\",\n\tdateFormat: \"yy. m. d.\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: true,\n\tyearSuffix: \"\ub144\" };\ndatepicker.setDefaults( datepicker.regional.ko );\n\nreturn datepicker.regional.ko;\n\n} );\n","jquery/ui-modules/i18n/datepicker-hi.js":"/* Hindi initialisation for the jQuery UI date picker plugin. */\n/* Written by Michael Dawart. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.hi = {\n\tcloseText: \"\u092c\u0902\u0926\",\n\tprevText: \"\u092a\u093f\u091b\u0932\u093e\",\n\tnextText: \"\u0905\u0917\u0932\u093e\",\n\tcurrentText: \"\u0906\u091c\",\n\tmonthNames: [ \"\u091c\u0928\u0935\u0930\u0940 \", \"\u092b\u0930\u0935\u0930\u0940\", \"\u092e\u093e\u0930\u094d\u091a\", \"\u0905\u092a\u094d\u0930\u0947\u0932\", \"\u092e\u0908\", \"\u091c\u0942\u0928\",\n\t\"\u091c\u0942\u0932\u093e\u0908\", \"\u0905\u0917\u0938\u094d\u0924 \", \"\u0938\u093f\u0924\u092e\u094d\u092c\u0930\", \"\u0905\u0915\u094d\u091f\u0942\u092c\u0930\", \"\u0928\u0935\u092e\u094d\u092c\u0930\", \"\u0926\u093f\u0938\u092e\u094d\u092c\u0930\" ],\n\tmonthNamesShort: [ \"\u091c\u0928\", \"\u092b\u0930\", \"\u092e\u093e\u0930\u094d\u091a\", \"\u0905\u092a\u094d\u0930\u0947\u0932\", \"\u092e\u0908\", \"\u091c\u0942\u0928\",\n\t\"\u091c\u0942\u0932\u093e\u0908\", \"\u0905\u0917\", \"\u0938\u093f\u0924\", \"\u0905\u0915\u094d\u091f\", \"\u0928\u0935\", \"\u0926\u093f\" ],\n\tdayNames: [ \"\u0930\u0935\u093f\u0935\u093e\u0930\", \"\u0938\u094b\u092e\u0935\u093e\u0930\", \"\u092e\u0902\u0917\u0932\u0935\u093e\u0930\", \"\u092c\u0941\u0927\u0935\u093e\u0930\", \"\u0917\u0941\u0930\u0941\u0935\u093e\u0930\", \"\u0936\u0941\u0915\u094d\u0930\u0935\u093e\u0930\", \"\u0936\u0928\u093f\u0935\u093e\u0930\" ],\n\tdayNamesShort: [ \"\u0930\u0935\u093f\", \"\u0938\u094b\u092e\", \"\u092e\u0902\u0917\u0932\", \"\u092c\u0941\u0927\", \"\u0917\u0941\u0930\u0941\", \"\u0936\u0941\u0915\u094d\u0930\", \"\u0936\u0928\u093f\" ],\n\tdayNamesMin: [ \"\u0930\u0935\u093f\", \"\u0938\u094b\u092e\", \"\u092e\u0902\u0917\u0932\", \"\u092c\u0941\u0927\", \"\u0917\u0941\u0930\u0941\", \"\u0936\u0941\u0915\u094d\u0930\", \"\u0936\u0928\u093f\" ],\n\tweekHeader: \"\u0939\u092b\u094d\u0924\u093e\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.hi );\n\nreturn datepicker.regional.hi;\n\n} );\n","jquery/ui-modules/i18n/datepicker-nn.js":"/* Norwegian Nynorsk initialisation for the jQuery UI date picker plugin. */\n/* Written by Bj\u00f8rn Johansen ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.nn = {\n\tcloseText: \"Lukk\",\n\tprevText: \"&#xAB;F\u00f8rre\",\n\tnextText: \"Neste&#xBB;\",\n\tcurrentText: \"I dag\",\n\tmonthNames: [\n\t\t\"januar\",\n\t\t\"februar\",\n\t\t\"mars\",\n\t\t\"april\",\n\t\t\"mai\",\n\t\t\"juni\",\n\t\t\"juli\",\n\t\t\"august\",\n\t\t\"september\",\n\t\t\"oktober\",\n\t\t\"november\",\n\t\t\"desember\"\n\t],\n\tmonthNamesShort: [ \"jan\", \"feb\", \"mar\", \"apr\", \"mai\", \"jun\", \"jul\", \"aug\", \"sep\", \"okt\", \"nov\", \"des\" ],\n\tdayNamesShort: [ \"sun\", \"m\u00e5n\", \"tys\", \"ons\", \"tor\", \"fre\", \"lau\" ],\n\tdayNames: [ \"sundag\", \"m\u00e5ndag\", \"tysdag\", \"onsdag\", \"torsdag\", \"fredag\", \"laurdag\" ],\n\tdayNamesMin: [ \"su\", \"m\u00e5\", \"ty\", \"on\", \"to\", \"fr\", \"la\" ],\n\tweekHeader: \"Veke\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\"\n};\ndatepicker.setDefaults( datepicker.regional.nn );\n\nreturn datepicker.regional.nn;\n\n} );\n","jquery/ui-modules/i18n/datepicker-nl-BE.js":"/* Dutch (Belgium) initialisation for the jQuery UI date picker plugin. */\n/* David De Sloovere @DavidDeSloovere */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"nl-BE\" ] = {\n\tcloseText: \"Sluiten\",\n\tprevText: \"\u2190\",\n\tnextText: \"\u2192\",\n\tcurrentText: \"Vandaag\",\n\tmonthNames: [ \"januari\", \"februari\", \"maart\", \"april\", \"mei\", \"juni\",\n\t\"juli\", \"augustus\", \"september\", \"oktober\", \"november\", \"december\" ],\n\tmonthNamesShort: [ \"jan\", \"feb\", \"mrt\", \"apr\", \"mei\", \"jun\",\n\t\"jul\", \"aug\", \"sep\", \"okt\", \"nov\", \"dec\" ],\n\tdayNames: [ \"zondag\", \"maandag\", \"dinsdag\", \"woensdag\", \"donderdag\", \"vrijdag\", \"zaterdag\" ],\n\tdayNamesShort: [ \"zon\", \"maa\", \"din\", \"woe\", \"don\", \"vri\", \"zat\" ],\n\tdayNamesMin: [ \"zo\", \"ma\", \"di\", \"wo\", \"do\", \"vr\", \"za\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional[ \"nl-BE\" ] );\n\nreturn datepicker.regional[ \"nl-BE\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-mk.js":"/* Macedonian i18n for the jQuery UI date picker plugin. */\n/* Written by Stojce Slavkovski. */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.mk = {\n\tcloseText: \"\u0417\u0430\u0442\u0432\u043e\u0440\u0438\",\n\tprevText: \"&#x3C;\",\n\tnextText: \"&#x3E;\",\n\tcurrentText: \"\u0414\u0435\u043d\u0435\u0441\",\n\tmonthNames: [ \"\u0408\u0430\u043d\u0443\u0430\u0440\u0438\", \"\u0424\u0435\u0432\u0440\u0443\u0430\u0440\u0438\", \"\u041c\u0430\u0440\u0442\", \"\u0410\u043f\u0440\u0438\u043b\", \"\u041c\u0430\u0458\", \"\u0408\u0443\u043d\u0438\",\n\t\"\u0408\u0443\u043b\u0438\", \"\u0410\u0432\u0433\u0443\u0441\u0442\", \"\u0421\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438\", \"\u041e\u043a\u0442\u043e\u043c\u0432\u0440\u0438\", \"\u041d\u043e\u0435\u043c\u0432\u0440\u0438\", \"\u0414\u0435\u043a\u0435\u043c\u0432\u0440\u0438\" ],\n\tmonthNamesShort: [ \"\u0408\u0430\u043d\", \"\u0424\u0435\u0432\", \"\u041c\u0430\u0440\", \"\u0410\u043f\u0440\", \"\u041c\u0430\u0458\", \"\u0408\u0443\u043d\",\n\t\"\u0408\u0443\u043b\", \"\u0410\u0432\u0433\", \"\u0421\u0435\u043f\", \"\u041e\u043a\u0442\", \"\u041d\u043e\u0435\", \"\u0414\u0435\u043a\" ],\n\tdayNames: [ \"\u041d\u0435\u0434\u0435\u043b\u0430\", \"\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u043d\u0438\u043a\", \"\u0412\u0442\u043e\u0440\u043d\u0438\u043a\", \"\u0421\u0440\u0435\u0434\u0430\", \"\u0427\u0435\u0442\u0432\u0440\u0442\u043e\u043a\", \"\u041f\u0435\u0442\u043e\u043a\", \"\u0421\u0430\u0431\u043e\u0442\u0430\" ],\n\tdayNamesShort: [ \"\u041d\u0435\u0434\", \"\u041f\u043e\u043d\", \"\u0412\u0442\u043e\", \"\u0421\u0440\u0435\", \"\u0427\u0435\u0442\", \"\u041f\u0435\u0442\", \"\u0421\u0430\u0431\" ],\n\tdayNamesMin: [ \"\u041d\u0435\", \"\u041f\u043e\", \"\u0412\u0442\", \"\u0421\u0440\", \"\u0427\u0435\", \"\u041f\u0435\", \"\u0421\u0430\" ],\n\tweekHeader: \"\u0421\u0435\u0434\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.mk );\n\nreturn datepicker.regional.mk;\n\n} );\n","jquery/ui-modules/i18n/datepicker-is.js":"/* Icelandic initialisation for the jQuery UI date picker plugin. */\n/* Written by Haukur H. Thorsson ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.is = {\n\tcloseText: \"Loka\",\n\tprevText: \"&#x3C; Fyrri\",\n\tnextText: \"N\u00e6sti &#x3E;\",\n\tcurrentText: \"\u00cd dag\",\n\tmonthNames: [ \"Jan\u00faar\", \"Febr\u00faar\", \"Mars\", \"Apr\u00edl\", \"Ma\u00ed\", \"J\u00fan\u00ed\",\n\t\"J\u00fal\u00ed\", \"\u00c1g\u00fast\", \"September\", \"Okt\u00f3ber\", \"N\u00f3vember\", \"Desember\" ],\n\tmonthNamesShort: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Ma\u00ed\", \"J\u00fan\",\n\t\"J\u00fal\", \"\u00c1g\u00fa\", \"Sep\", \"Okt\", \"N\u00f3v\", \"Des\" ],\n\tdayNames: [\n\t\t\"Sunnudagur\",\n\t\t\"M\u00e1nudagur\",\n\t\t\"\u00deri\u00f0judagur\",\n\t\t\"Mi\u00f0vikudagur\",\n\t\t\"Fimmtudagur\",\n\t\t\"F\u00f6studagur\",\n\t\t\"Laugardagur\"\n\t],\n\tdayNamesShort: [ \"Sun\", \"M\u00e1n\", \"\u00deri\", \"Mi\u00f0\", \"Fim\", \"F\u00f6s\", \"Lau\" ],\n\tdayNamesMin: [ \"Su\", \"M\u00e1\", \"\u00der\", \"Mi\", \"Fi\", \"F\u00f6\", \"La\" ],\n\tweekHeader: \"Vika\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.is );\n\nreturn datepicker.regional.is;\n\n} );\n","jquery/ui-modules/i18n/datepicker-uk.js":"/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Maxim Drogobitskiy ([email protected]). */\n/* Corrected by Igor Milla ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.uk = {\n\tcloseText: \"\u0417\u0430\u043a\u0440\u0438\u0442\u0438\",\n\tprevText: \"&#x3C;\",\n\tnextText: \"&#x3E;\",\n\tcurrentText: \"\u0421\u044c\u043e\u0433\u043e\u0434\u043d\u0456\",\n\tmonthNames: [ \"\u0421\u0456\u0447\u0435\u043d\u044c\", \"\u041b\u044e\u0442\u0438\u0439\", \"\u0411\u0435\u0440\u0435\u0437\u0435\u043d\u044c\", \"\u041a\u0432\u0456\u0442\u0435\u043d\u044c\", \"\u0422\u0440\u0430\u0432\u0435\u043d\u044c\", \"\u0427\u0435\u0440\u0432\u0435\u043d\u044c\",\n\t\"\u041b\u0438\u043f\u0435\u043d\u044c\", \"\u0421\u0435\u0440\u043f\u0435\u043d\u044c\", \"\u0412\u0435\u0440\u0435\u0441\u0435\u043d\u044c\", \"\u0416\u043e\u0432\u0442\u0435\u043d\u044c\", \"\u041b\u0438\u0441\u0442\u043e\u043f\u0430\u0434\", \"\u0413\u0440\u0443\u0434\u0435\u043d\u044c\" ],\n\tmonthNamesShort: [ \"\u0421\u0456\u0447\", \"\u041b\u044e\u0442\", \"\u0411\u0435\u0440\", \"\u041a\u0432\u0456\", \"\u0422\u0440\u0430\", \"\u0427\u0435\u0440\",\n\t\"\u041b\u0438\u043f\", \"\u0421\u0435\u0440\", \"\u0412\u0435\u0440\", \"\u0416\u043e\u0432\", \"\u041b\u0438\u0441\", \"\u0413\u0440\u0443\" ],\n\tdayNames: [ \"\u043d\u0435\u0434\u0456\u043b\u044f\", \"\u043f\u043e\u043d\u0435\u0434\u0456\u043b\u043e\u043a\", \"\u0432\u0456\u0432\u0442\u043e\u0440\u043e\u043a\", \"\u0441\u0435\u0440\u0435\u0434\u0430\", \"\u0447\u0435\u0442\u0432\u0435\u0440\", \"\u043f\u2019\u044f\u0442\u043d\u0438\u0446\u044f\", \"\u0441\u0443\u0431\u043e\u0442\u0430\" ],\n\tdayNamesShort: [ \"\u043d\u0435\u0434\", \"\u043f\u043d\u0434\", \"\u0432\u0456\u0432\", \"\u0441\u0440\u0434\", \"\u0447\u0442\u0432\", \"\u043f\u0442\u043d\", \"\u0441\u0431\u0442\" ],\n\tdayNamesMin: [ \"\u041d\u0434\", \"\u041f\u043d\", \"\u0412\u0442\", \"\u0421\u0440\", \"\u0427\u0442\", \"\u041f\u0442\", \"\u0421\u0431\" ],\n\tweekHeader: \"\u0422\u0438\u0436\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.uk );\n\nreturn datepicker.regional.uk;\n\n} );\n","jquery/ui-modules/i18n/datepicker-vi.js":"/* Vietnamese initialisation for the jQuery UI date picker plugin. */\n/* Translated by Le Thanh Huy ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.vi = {\n\tcloseText: \"\u0110\u00f3ng\",\n\tprevText: \"&#x3C;Tr\u01b0\u1edbc\",\n\tnextText: \"Ti\u1ebfp&#x3E;\",\n\tcurrentText: \"H\u00f4m nay\",\n\tmonthNames: [ \"Th\u00e1ng M\u1ed9t\", \"Th\u00e1ng Hai\", \"Th\u00e1ng Ba\", \"Th\u00e1ng T\u01b0\", \"Th\u00e1ng N\u0103m\", \"Th\u00e1ng S\u00e1u\",\n\t\"Th\u00e1ng B\u1ea3y\", \"Th\u00e1ng T\u00e1m\", \"Th\u00e1ng Ch\u00edn\", \"Th\u00e1ng M\u01b0\u1eddi\", \"Th\u00e1ng M\u01b0\u1eddi M\u1ed9t\", \"Th\u00e1ng M\u01b0\u1eddi Hai\" ],\n\tmonthNamesShort: [ \"Th\u00e1ng 1\", \"Th\u00e1ng 2\", \"Th\u00e1ng 3\", \"Th\u00e1ng 4\", \"Th\u00e1ng 5\", \"Th\u00e1ng 6\",\n\t\"Th\u00e1ng 7\", \"Th\u00e1ng 8\", \"Th\u00e1ng 9\", \"Th\u00e1ng 10\", \"Th\u00e1ng 11\", \"Th\u00e1ng 12\" ],\n\tdayNames: [ \"Ch\u1ee7 Nh\u1eadt\", \"Th\u1ee9 Hai\", \"Th\u1ee9 Ba\", \"Th\u1ee9 T\u01b0\", \"Th\u1ee9 N\u0103m\", \"Th\u1ee9 S\u00e1u\", \"Th\u1ee9 B\u1ea3y\" ],\n\tdayNamesShort: [ \"CN\", \"T2\", \"T3\", \"T4\", \"T5\", \"T6\", \"T7\" ],\n\tdayNamesMin: [ \"CN\", \"T2\", \"T3\", \"T4\", \"T5\", \"T6\", \"T7\" ],\n\tweekHeader: \"Tu\",\n\tdateFormat: \"dd/mm/yy\",\n\tfirstDay: 0,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.vi );\n\nreturn datepicker.regional.vi;\n\n} );\n","jquery/ui-modules/i18n/datepicker-zh-CN.js":"/* Chinese initialisation for the jQuery UI date picker plugin. */\n/* Written by Cloudream ([email protected]). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional[ \"zh-CN\" ] = {\n\tcloseText: \"\u5173\u95ed\",\n\tprevText: \"&#x3C;\u4e0a\u6708\",\n\tnextText: \"\u4e0b\u6708&#x3E;\",\n\tcurrentText: \"\u4eca\u5929\",\n\tmonthNames: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tmonthNamesShort: [ \"\u4e00\u6708\", \"\u4e8c\u6708\", \"\u4e09\u6708\", \"\u56db\u6708\", \"\u4e94\u6708\", \"\u516d\u6708\",\n\t\"\u4e03\u6708\", \"\u516b\u6708\", \"\u4e5d\u6708\", \"\u5341\u6708\", \"\u5341\u4e00\u6708\", \"\u5341\u4e8c\u6708\" ],\n\tdayNames: [ \"\u661f\u671f\u65e5\", \"\u661f\u671f\u4e00\", \"\u661f\u671f\u4e8c\", \"\u661f\u671f\u4e09\", \"\u661f\u671f\u56db\", \"\u661f\u671f\u4e94\", \"\u661f\u671f\u516d\" ],\n\tdayNamesShort: [ \"\u5468\u65e5\", \"\u5468\u4e00\", \"\u5468\u4e8c\", \"\u5468\u4e09\", \"\u5468\u56db\", \"\u5468\u4e94\", \"\u5468\u516d\" ],\n\tdayNamesMin: [ \"\u65e5\", \"\u4e00\", \"\u4e8c\", \"\u4e09\", \"\u56db\", \"\u4e94\", \"\u516d\" ],\n\tweekHeader: \"\u5468\",\n\tdateFormat: \"yy-mm-dd\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: true,\n\tyearSuffix: \"\u5e74\" };\ndatepicker.setDefaults( datepicker.regional[ \"zh-CN\" ] );\n\nreturn datepicker.regional[ \"zh-CN\" ];\n\n} );\n","jquery/ui-modules/i18n/datepicker-bg.js":"/* Bulgarian initialisation for the jQuery UI date picker plugin. */\n/* Written by Stoyan Kyosev (http://svest.org). */\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"../widgets/datepicker\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery.datepicker );\n\t}\n} )( function( datepicker ) {\n\"use strict\";\n\ndatepicker.regional.bg = {\n\tcloseText: \"\u0437\u0430\u0442\u0432\u043e\u0440\u0438\",\n\tprevText: \"&#x3C;\u043d\u0430\u0437\u0430\u0434\",\n\tnextText: \"\u043d\u0430\u043f\u0440\u0435\u0434&#x3E;\",\n\tnextBigText: \"&#x3E;&#x3E;\",\n\tcurrentText: \"\u0434\u043d\u0435\u0441\",\n\tmonthNames: [ \"\u042f\u043d\u0443\u0430\u0440\u0438\", \"\u0424\u0435\u0432\u0440\u0443\u0430\u0440\u0438\", \"\u041c\u0430\u0440\u0442\", \"\u0410\u043f\u0440\u0438\u043b\", \"\u041c\u0430\u0439\", \"\u042e\u043d\u0438\",\n\t\"\u042e\u043b\u0438\", \"\u0410\u0432\u0433\u0443\u0441\u0442\", \"\u0421\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438\", \"\u041e\u043a\u0442\u043e\u043c\u0432\u0440\u0438\", \"\u041d\u043e\u0435\u043c\u0432\u0440\u0438\", \"\u0414\u0435\u043a\u0435\u043c\u0432\u0440\u0438\" ],\n\tmonthNamesShort: [ \"\u042f\u043d\u0443\", \"\u0424\u0435\u0432\", \"\u041c\u0430\u0440\", \"\u0410\u043f\u0440\", \"\u041c\u0430\u0439\", \"\u042e\u043d\u0438\",\n\t\"\u042e\u043b\u0438\", \"\u0410\u0432\u0433\", \"\u0421\u0435\u043f\", \"\u041e\u043a\u0442\", \"\u041d\u043e\u0432\", \"\u0414\u0435\u043a\" ],\n\tdayNames: [ \"\u041d\u0435\u0434\u0435\u043b\u044f\", \"\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u043d\u0438\u043a\", \"\u0412\u0442\u043e\u0440\u043d\u0438\u043a\", \"\u0421\u0440\u044f\u0434\u0430\", \"\u0427\u0435\u0442\u0432\u044a\u0440\u0442\u044a\u043a\", \"\u041f\u0435\u0442\u044a\u043a\", \"\u0421\u044a\u0431\u043e\u0442\u0430\" ],\n\tdayNamesShort: [ \"\u041d\u0435\u0434\", \"\u041f\u043e\u043d\", \"\u0412\u0442\u043e\", \"\u0421\u0440\u044f\", \"\u0427\u0435\u0442\", \"\u041f\u0435\u0442\", \"\u0421\u044a\u0431\" ],\n\tdayNamesMin: [ \"\u041d\u0435\", \"\u041f\u043e\", \"\u0412\u0442\", \"\u0421\u0440\", \"\u0427\u0435\", \"\u041f\u0435\", \"\u0421\u044a\" ],\n\tweekHeader: \"Wk\",\n\tdateFormat: \"dd.mm.yy\",\n\tfirstDay: 1,\n\tisRTL: false,\n\tshowMonthAfterYear: false,\n\tyearSuffix: \"\" };\ndatepicker.setDefaults( datepicker.regional.bg );\n\nreturn datepicker.regional.bg;\n\n} );\n","jquery/ui-modules/effects/effect-explode.js":"/*!\n * jQuery UI Effects Explode 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Explode Effect\n//>>group: Effects\n/* eslint-disable max-len */\n//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.\n/* eslint-enable max-len */\n//>>docs: http://api.jqueryui.com/explode-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"explode\", \"hide\", function( options, done ) {\n\n        var i, j, left, top, mx, my,\n            rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,\n            cells = rows,\n            element = $( this ),\n            mode = options.mode,\n            show = mode === \"show\",\n\n            // Show and then visibility:hidden the element before calculating offset\n            offset = element.show().css( \"visibility\", \"hidden\" ).offset(),\n\n            // Width and height of a piece\n            width = Math.ceil( element.outerWidth() / cells ),\n            height = Math.ceil( element.outerHeight() / rows ),\n            pieces = [];\n\n        // Children animate complete:\n        function childComplete() {\n            pieces.push( this );\n            if ( pieces.length === rows * cells ) {\n                animComplete();\n            }\n        }\n\n        // Clone the element for each row and cell.\n        for ( i = 0; i < rows; i++ ) { // ===>\n            top = offset.top + i * height;\n            my = i - ( rows - 1 ) / 2;\n\n            for ( j = 0; j < cells; j++ ) { // |||\n                left = offset.left + j * width;\n                mx = j - ( cells - 1 ) / 2;\n\n                // Create a clone of the now hidden main element that will be absolute positioned\n                // within a wrapper div off the -left and -top equal to size of our pieces\n                element\n                    .clone()\n                    .appendTo( \"body\" )\n                    .wrap( \"<div></div>\" )\n                    .css( {\n                        position: \"absolute\",\n                        visibility: \"visible\",\n                        left: -j * width,\n                        top: -i * height\n                    } )\n\n                    // Select the wrapper - make it overflow: hidden and absolute positioned based on\n                    // where the original was located +left and +top equal to the size of pieces\n                    .parent()\n                    .addClass( \"ui-effects-explode\" )\n                    .css( {\n                        position: \"absolute\",\n                        overflow: \"hidden\",\n                        width: width,\n                        height: height,\n                        left: left + ( show ? mx * width : 0 ),\n                        top: top + ( show ? my * height : 0 ),\n                        opacity: show ? 0 : 1\n                    } )\n                    .animate( {\n                        left: left + ( show ? 0 : mx * width ),\n                        top: top + ( show ? 0 : my * height ),\n                        opacity: show ? 1 : 0\n                    }, options.duration || 500, options.easing, childComplete );\n            }\n        }\n\n        function animComplete() {\n            element.css( {\n                visibility: \"visible\"\n            } );\n            $( pieces ).remove();\n            done();\n        }\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-drop.js":"/*!\n * jQuery UI Effects Clip 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Clip Effect\n//>>group: Effects\n//>>description: Clips the element on and off like an old TV.\n//>>docs: http://api.jqueryui.com/clip-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"clip\", \"hide\", function( options, done ) {\n        var start,\n            animate = {},\n            element = $( this ),\n            direction = options.direction || \"vertical\",\n            both = direction === \"both\",\n            horizontal = both || direction === \"horizontal\",\n            vertical = both || direction === \"vertical\";\n\n        start = element.cssClip();\n        animate.clip = {\n            top: vertical ? ( start.bottom - start.top ) / 2 : start.top,\n            right: horizontal ? ( start.right - start.left ) / 2 : start.right,\n            bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,\n            left: horizontal ? ( start.right - start.left ) / 2 : start.left\n        };\n\n        $.effects.createPlaceholder( element );\n\n        if ( options.mode === \"show\" ) {\n            element.cssClip( animate.clip );\n            animate.clip = start;\n        }\n\n        element.animate( animate, {\n            queue: false,\n            duration: options.duration,\n            easing: options.easing,\n            complete: done\n        } );\n\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-size.js":"/*!\n * jQuery UI Effects Size 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Size Effect\n//>>group: Effects\n//>>description: Resize an element to a specified width and height.\n//>>docs: http://api.jqueryui.com/size-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"size\", function( options, done ) {\n\n        // Create element\n        var baseline, factor, temp,\n            element = $( this ),\n\n            // Copy for children\n            cProps = [ \"fontSize\" ],\n            vProps = [ \"borderTopWidth\", \"borderBottomWidth\", \"paddingTop\", \"paddingBottom\" ],\n            hProps = [ \"borderLeftWidth\", \"borderRightWidth\", \"paddingLeft\", \"paddingRight\" ],\n\n            // Set options\n            mode = options.mode,\n            restore = mode !== \"effect\",\n            scale = options.scale || \"both\",\n            origin = options.origin || [ \"middle\", \"center\" ],\n            position = element.css( \"position\" ),\n            pos = element.position(),\n            original = $.effects.scaledDimensions( element ),\n            from = options.from || original,\n            to = options.to || $.effects.scaledDimensions( element, 0 );\n\n        $.effects.createPlaceholder( element );\n\n        if ( mode === \"show\" ) {\n            temp = from;\n            from = to;\n            to = temp;\n        }\n\n        // Set scaling factor\n        factor = {\n            from: {\n                y: from.height / original.height,\n                x: from.width / original.width\n            },\n            to: {\n                y: to.height / original.height,\n                x: to.width / original.width\n            }\n        };\n\n        // Scale the css box\n        if ( scale === \"box\" || scale === \"both\" ) {\n\n            // Vertical props scaling\n            if ( factor.from.y !== factor.to.y ) {\n                from = $.effects.setTransition( element, vProps, factor.from.y, from );\n                to = $.effects.setTransition( element, vProps, factor.to.y, to );\n            }\n\n            // Horizontal props scaling\n            if ( factor.from.x !== factor.to.x ) {\n                from = $.effects.setTransition( element, hProps, factor.from.x, from );\n                to = $.effects.setTransition( element, hProps, factor.to.x, to );\n            }\n        }\n\n        // Scale the content\n        if ( scale === \"content\" || scale === \"both\" ) {\n\n            // Vertical props scaling\n            if ( factor.from.y !== factor.to.y ) {\n                from = $.effects.setTransition( element, cProps, factor.from.y, from );\n                to = $.effects.setTransition( element, cProps, factor.to.y, to );\n            }\n        }\n\n        // Adjust the position properties based on the provided origin points\n        if ( origin ) {\n            baseline = $.effects.getBaseline( origin, original );\n            from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;\n            from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;\n            to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;\n            to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;\n        }\n        delete from.outerHeight;\n        delete from.outerWidth;\n        element.css( from );\n\n        // Animate the children if desired\n        if ( scale === \"content\" || scale === \"both\" ) {\n\n            vProps = vProps.concat( [ \"marginTop\", \"marginBottom\" ] ).concat( cProps );\n            hProps = hProps.concat( [ \"marginLeft\", \"marginRight\" ] );\n\n            // Only animate children with width attributes specified\n            // TODO: is this right? should we include anything with css width specified as well\n            element.find( \"*[width]\" ).each( function() {\n                var child = $( this ),\n                    childOriginal = $.effects.scaledDimensions( child ),\n                    childFrom = {\n                        height: childOriginal.height * factor.from.y,\n                        width: childOriginal.width * factor.from.x,\n                        outerHeight: childOriginal.outerHeight * factor.from.y,\n                        outerWidth: childOriginal.outerWidth * factor.from.x\n                    },\n                    childTo = {\n                        height: childOriginal.height * factor.to.y,\n                        width: childOriginal.width * factor.to.x,\n                        outerHeight: childOriginal.height * factor.to.y,\n                        outerWidth: childOriginal.width * factor.to.x\n                    };\n\n                // Vertical props scaling\n                if ( factor.from.y !== factor.to.y ) {\n                    childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );\n                    childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );\n                }\n\n                // Horizontal props scaling\n                if ( factor.from.x !== factor.to.x ) {\n                    childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );\n                    childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );\n                }\n\n                if ( restore ) {\n                    $.effects.saveStyle( child );\n                }\n\n                // Animate children\n                child.css( childFrom );\n                child.animate( childTo, options.duration, options.easing, function() {\n\n                    // Restore children\n                    if ( restore ) {\n                        $.effects.restoreStyle( child );\n                    }\n                } );\n            } );\n        }\n\n        // Animate\n        element.animate( to, {\n            queue: false,\n            duration: options.duration,\n            easing: options.easing,\n            complete: function() {\n\n                var offset = element.offset();\n\n                if ( to.opacity === 0 ) {\n                    element.css( \"opacity\", from.opacity );\n                }\n\n                if ( !restore ) {\n                    element\n                        .css( \"position\", position === \"static\" ? \"relative\" : position )\n                        .offset( offset );\n\n                    // Need to save style here so that automatic style restoration\n                    // doesn't restore to the original styles from before the animation.\n                    $.effects.saveStyle( element );\n                }\n\n                done();\n            }\n        } );\n\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-fade.js":"/*!\n * jQuery UI Effects Fade 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Fade Effect\n//>>group: Effects\n//>>description: Fades the element.\n//>>docs: http://api.jqueryui.com/fade-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"fade\", \"toggle\", function( options, done ) {\n        var show = options.mode === \"show\";\n\n        $( this )\n            .css( \"opacity\", show ? 0 : 1 )\n            .animate( {\n                opacity: show ? 1 : 0\n            }, {\n                queue: false,\n                duration: options.duration,\n                easing: options.easing,\n                complete: done\n            } );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-shake.js":"/*!\n * jQuery UI Effects Shake 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Shake Effect\n//>>group: Effects\n//>>description: Shakes an element horizontally or vertically n times.\n//>>docs: http://api.jqueryui.com/shake-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"shake\", function( options, done ) {\n\n        var i = 1,\n            element = $( this ),\n            direction = options.direction || \"left\",\n            distance = options.distance || 20,\n            times = options.times || 3,\n            anims = times * 2 + 1,\n            speed = Math.round( options.duration / anims ),\n            ref = ( direction === \"up\" || direction === \"down\" ) ? \"top\" : \"left\",\n            positiveMotion = ( direction === \"up\" || direction === \"left\" ),\n            animation = {},\n            animation1 = {},\n            animation2 = {},\n\n            queuelen = element.queue().length;\n\n        $.effects.createPlaceholder( element );\n\n        // Animation\n        animation[ ref ] = ( positiveMotion ? \"-=\" : \"+=\" ) + distance;\n        animation1[ ref ] = ( positiveMotion ? \"+=\" : \"-=\" ) + distance * 2;\n        animation2[ ref ] = ( positiveMotion ? \"-=\" : \"+=\" ) + distance * 2;\n\n        // Animate\n        element.animate( animation, speed, options.easing );\n\n        // Shakes\n        for ( ; i < times; i++ ) {\n            element\n                .animate( animation1, speed, options.easing )\n                .animate( animation2, speed, options.easing );\n        }\n\n        element\n            .animate( animation1, speed, options.easing )\n            .animate( animation, speed / 2, options.easing )\n            .queue( done );\n\n        $.effects.unshift( element, queuelen, anims + 1 );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-bounce.js":"/*!\n * jQuery UI Effects Bounce 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Bounce Effect\n//>>group: Effects\n//>>description: Bounces an element horizontally or vertically n times.\n//>>docs: http://api.jqueryui.com/bounce-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"bounce\", function( options, done ) {\n        var upAnim, downAnim, refValue,\n            element = $( this ),\n\n            // Defaults:\n            mode = options.mode,\n            hide = mode === \"hide\",\n            show = mode === \"show\",\n            direction = options.direction || \"up\",\n            distance = options.distance,\n            times = options.times || 5,\n\n            // Number of internal animations\n            anims = times * 2 + ( show || hide ? 1 : 0 ),\n            speed = options.duration / anims,\n            easing = options.easing,\n\n            // Utility:\n            ref = ( direction === \"up\" || direction === \"down\" ) ? \"top\" : \"left\",\n            motion = ( direction === \"up\" || direction === \"left\" ),\n            i = 0,\n\n            queuelen = element.queue().length;\n\n        $.effects.createPlaceholder( element );\n\n        refValue = element.css( ref );\n\n        // Default distance for the BIGGEST bounce is the outer Distance / 3\n        if ( !distance ) {\n            distance = element[ ref === \"top\" ? \"outerHeight\" : \"outerWidth\" ]() / 3;\n        }\n\n        if ( show ) {\n            downAnim = { opacity: 1 };\n            downAnim[ ref ] = refValue;\n\n            // If we are showing, force opacity 0 and set the initial position\n            // then do the \"first\" animation\n            element\n                .css( \"opacity\", 0 )\n                .css( ref, motion ? -distance * 2 : distance * 2 )\n                .animate( downAnim, speed, easing );\n        }\n\n        // Start at the smallest distance if we are hiding\n        if ( hide ) {\n            distance = distance / Math.pow( 2, times - 1 );\n        }\n\n        downAnim = {};\n        downAnim[ ref ] = refValue;\n\n        // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here\n        for ( ; i < times; i++ ) {\n            upAnim = {};\n            upAnim[ ref ] = ( motion ? \"-=\" : \"+=\" ) + distance;\n\n            element\n                .animate( upAnim, speed, easing )\n                .animate( downAnim, speed, easing );\n\n            distance = hide ? distance * 2 : distance / 2;\n        }\n\n        // Last Bounce when Hiding\n        if ( hide ) {\n            upAnim = { opacity: 0 };\n            upAnim[ ref ] = ( motion ? \"-=\" : \"+=\" ) + distance;\n\n            element.animate( upAnim, speed, easing );\n        }\n\n        element.queue( done );\n\n        $.effects.unshift( element, queuelen, anims + 1 );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-highlight.js":"/*!\n * jQuery UI Effects Highlight 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Highlight Effect\n//>>group: Effects\n//>>description: Highlights the background of an element in a defined color for a custom duration.\n//>>docs: http://api.jqueryui.com/highlight-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"highlight\", \"show\", function( options, done ) {\n        var element = $( this ),\n            animation = {\n                backgroundColor: element.css( \"backgroundColor\" )\n            };\n\n        if ( options.mode === \"hide\" ) {\n            animation.opacity = 0;\n        }\n\n        $.effects.saveStyle( element );\n\n        element\n            .css( {\n                backgroundImage: \"none\",\n                backgroundColor: options.color || \"#ffff99\"\n            } )\n            .animate( animation, {\n                queue: false,\n                duration: options.duration,\n                easing: options.easing,\n                complete: done\n            } );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-pulsate.js":"/*!\n * jQuery UI Effects Pulsate 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Pulsate Effect\n//>>group: Effects\n//>>description: Pulsates an element n times by changing the opacity to zero and back.\n//>>docs: http://api.jqueryui.com/pulsate-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"pulsate\", \"show\", function( options, done ) {\n        var element = $( this ),\n            mode = options.mode,\n            show = mode === \"show\",\n            hide = mode === \"hide\",\n            showhide = show || hide,\n\n            // Showing or hiding leaves off the \"last\" animation\n            anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),\n            duration = options.duration / anims,\n            animateTo = 0,\n            i = 1,\n            queuelen = element.queue().length;\n\n        if ( show || !element.is( \":visible\" ) ) {\n            element.css( \"opacity\", 0 ).show();\n            animateTo = 1;\n        }\n\n        // Anims - 1 opacity \"toggles\"\n        for ( ; i < anims; i++ ) {\n            element.animate( { opacity: animateTo }, duration, options.easing );\n            animateTo = 1 - animateTo;\n        }\n\n        element.animate( { opacity: animateTo }, duration, options.easing );\n\n        element.queue( done );\n\n        $.effects.unshift( element, queuelen, anims + 1 );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-clip.js":"/*!\n * jQuery UI Effects Clip 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Clip Effect\n//>>group: Effects\n//>>description: Clips the element on and off like an old TV.\n//>>docs: http://api.jqueryui.com/clip-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"clip\", \"hide\", function( options, done ) {\n        var start,\n            animate = {},\n            element = $( this ),\n            direction = options.direction || \"vertical\",\n            both = direction === \"both\",\n            horizontal = both || direction === \"horizontal\",\n            vertical = both || direction === \"vertical\";\n\n        start = element.cssClip();\n        animate.clip = {\n            top: vertical ? ( start.bottom - start.top ) / 2 : start.top,\n            right: horizontal ? ( start.right - start.left ) / 2 : start.right,\n            bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,\n            left: horizontal ? ( start.right - start.left ) / 2 : start.left\n        };\n\n        $.effects.createPlaceholder( element );\n\n        if ( options.mode === \"show\" ) {\n            element.cssClip( animate.clip );\n            animate.clip = start;\n        }\n\n        element.animate( animate, {\n            queue: false,\n            duration: options.duration,\n            easing: options.easing,\n            complete: done\n        } );\n\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-scale.js":"/*!\n * jQuery UI Effects Scale 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Scale Effect\n//>>group: Effects\n//>>description: Grows or shrinks an element and its content.\n//>>docs: http://api.jqueryui.com/scale-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\",\n            \"./effect-size\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"scale\", function( options, done ) {\n\n        // Create element\n        var el = $( this ),\n            mode = options.mode,\n            percent = parseInt( options.percent, 10 ) ||\n                ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== \"effect\" ? 0 : 100 ) ),\n\n            newOptions = $.extend( true, {\n                from: $.effects.scaledDimensions( el ),\n                to: $.effects.scaledDimensions( el, percent, options.direction || \"both\" ),\n                origin: options.origin || [ \"middle\", \"center\" ]\n            }, options );\n\n        // Fade option to support puff\n        if ( options.fade ) {\n            newOptions.from.opacity = 1;\n            newOptions.to.opacity = 0;\n        }\n\n        $.effects.effect.size.call( this, newOptions, done );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-fold.js":"/*!\n * jQuery UI Effects Fold 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Fold Effect\n//>>group: Effects\n//>>description: Folds an element first horizontally and then vertically.\n//>>docs: http://api.jqueryui.com/fold-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"fold\", \"hide\", function( options, done ) {\n\n        // Create element\n        var element = $( this ),\n            mode = options.mode,\n            show = mode === \"show\",\n            hide = mode === \"hide\",\n            size = options.size || 15,\n            percent = /([0-9]+)%/.exec( size ),\n            horizFirst = !!options.horizFirst,\n            ref = horizFirst ? [ \"right\", \"bottom\" ] : [ \"bottom\", \"right\" ],\n            duration = options.duration / 2,\n\n            placeholder = $.effects.createPlaceholder( element ),\n\n            start = element.cssClip(),\n            animation1 = { clip: $.extend( {}, start ) },\n            animation2 = { clip: $.extend( {}, start ) },\n\n            distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],\n\n            queuelen = element.queue().length;\n\n        if ( percent ) {\n            size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];\n        }\n        animation1.clip[ ref[ 0 ] ] = size;\n        animation2.clip[ ref[ 0 ] ] = size;\n        animation2.clip[ ref[ 1 ] ] = 0;\n\n        if ( show ) {\n            element.cssClip( animation2.clip );\n            if ( placeholder ) {\n                placeholder.css( $.effects.clipToBox( animation2 ) );\n            }\n\n            animation2.clip = start;\n        }\n\n        // Animate\n        element\n            .queue( function( next ) {\n                if ( placeholder ) {\n                    placeholder\n                        .animate( $.effects.clipToBox( animation1 ), duration, options.easing )\n                        .animate( $.effects.clipToBox( animation2 ), duration, options.easing );\n                }\n\n                next();\n            } )\n            .animate( animation1, duration, options.easing )\n            .animate( animation2, duration, options.easing )\n            .queue( done );\n\n        $.effects.unshift( element, queuelen, 4 );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-blind.js":"/*!\n * jQuery UI Effects Blind 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Blind Effect\n//>>group: Effects\n//>>description: Blinds the element.\n//>>docs: http://api.jqueryui.com/blind-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"blind\", \"hide\", function( options, done ) {\n        var map = {\n                up: [ \"bottom\", \"top\" ],\n                vertical: [ \"bottom\", \"top\" ],\n                down: [ \"top\", \"bottom\" ],\n                left: [ \"right\", \"left\" ],\n                horizontal: [ \"right\", \"left\" ],\n                right: [ \"left\", \"right\" ]\n            },\n            element = $( this ),\n            direction = options.direction || \"up\",\n            start = element.cssClip(),\n            animate = { clip: $.extend( {}, start ) },\n            placeholder = $.effects.createPlaceholder( element );\n\n        animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];\n\n        if ( options.mode === \"show\" ) {\n            element.cssClip( animate.clip );\n            if ( placeholder ) {\n                placeholder.css( $.effects.clipToBox( animate ) );\n            }\n\n            animate.clip = start;\n        }\n\n        if ( placeholder ) {\n            placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );\n        }\n\n        element.animate( animate, {\n            queue: false,\n            duration: options.duration,\n            easing: options.easing,\n            complete: done\n        } );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-slide.js":"/*!\n * jQuery UI Effects Slide 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Slide Effect\n//>>group: Effects\n//>>description: Slides an element in and out of the viewport.\n//>>docs: http://api.jqueryui.com/slide-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"slide\", \"show\", function( options, done ) {\n        var startClip, startRef,\n            element = $( this ),\n            map = {\n                up: [ \"bottom\", \"top\" ],\n                down: [ \"top\", \"bottom\" ],\n                left: [ \"right\", \"left\" ],\n                right: [ \"left\", \"right\" ]\n            },\n            mode = options.mode,\n            direction = options.direction || \"left\",\n            ref = ( direction === \"up\" || direction === \"down\" ) ? \"top\" : \"left\",\n            positiveMotion = ( direction === \"up\" || direction === \"left\" ),\n            distance = options.distance ||\n                element[ ref === \"top\" ? \"outerHeight\" : \"outerWidth\" ]( true ),\n            animation = {};\n\n        $.effects.createPlaceholder( element );\n\n        startClip = element.cssClip();\n        startRef = element.position()[ ref ];\n\n        // Define hide animation\n        animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;\n        animation.clip = element.cssClip();\n        animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];\n\n        // Reverse the animation if we're showing\n        if ( mode === \"show\" ) {\n            element.cssClip( animation.clip );\n            element.css( ref, animation[ ref ] );\n            animation.clip = startClip;\n            animation[ ref ] = startRef;\n        }\n\n        // Actually animate\n        element.animate( animation, {\n            queue: false,\n            duration: options.duration,\n            easing: options.easing,\n            complete: done\n        } );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-puff.js":"/*!\n * jQuery UI Effects Puff 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Puff Effect\n//>>group: Effects\n//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.\n//>>docs: http://api.jqueryui.com/puff-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\",\n            \"./effect-scale\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    return $.effects.define( \"puff\", \"hide\", function( options, done ) {\n        var newOptions = $.extend( true, {}, options, {\n            fade: true,\n            percent: parseInt( options.percent, 10 ) || 150\n        } );\n\n        $.effects.effect.scale.call( this, newOptions, done );\n    } );\n\n} );\n","jquery/ui-modules/effects/effect-transfer.js":"/*!\n * jQuery UI Effects Transfer 1.13.2\n * http://jqueryui.com\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n */\n\n//>>label: Transfer Effect\n//>>group: Effects\n//>>description: Displays a transfer effect from one element to another.\n//>>docs: http://api.jqueryui.com/transfer-effect/\n//>>demos: http://jqueryui.com/effect/\n\n( function( factory ) {\n    \"use strict\";\n\n    if ( typeof define === \"function\" && define.amd ) {\n\n        // AMD. Register as an anonymous module.\n        define( [\n            \"jquery\",\n            \"../version\",\n            \"../effect\"\n        ], factory );\n    } else {\n\n        // Browser globals\n        factory( jQuery );\n    }\n} )( function( $ ) {\n    \"use strict\";\n\n    var effect;\n    if ( $.uiBackCompat !== false ) {\n        effect = $.effects.define( \"transfer\", function( options, done ) {\n            $( this ).transfer( options, done );\n        } );\n    }\n    return effect;\n\n} );\n","jquery/ui-modules/vendor/jquery-color/jquery.color.js":"/*!\n * jQuery Color Animations v2.2.0\n * https://github.com/jquery/jquery-color\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license.\n * http://jquery.org/license\n *\n * Date: Sun May 10 09:02:36 2020 +0200\n */\n\n( function( root, factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\" ], factory );\n\t} else if ( typeof exports === \"object\" ) {\n\t\tmodule.exports = factory( require( \"jquery\" ) );\n\t} else {\n\t\tfactory( root.jQuery );\n\t}\n} )( this, function( jQuery, undefined ) {\n\n\tvar stepHooks = \"backgroundColor borderBottomColor borderLeftColor borderRightColor \" +\n\t\t\"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor\",\n\n\tclass2type = {},\n\ttoString = class2type.toString,\n\n\t// plusequals test for += 100 -= 100\n\trplusequals = /^([\\-+])=\\s*(\\d+\\.?\\d*)/,\n\n\t// a set of RE's that can match strings and generate color tuples.\n\tstringParsers = [ {\n\t\t\tre: /rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ],\n\t\t\t\t\texecResult[ 2 ],\n\t\t\t\t\texecResult[ 3 ],\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\tre: /rgba?\\(\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ] * 2.55,\n\t\t\t\t\texecResult[ 2 ] * 2.55,\n\t\t\t\t\texecResult[ 3 ] * 2.55,\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\n\t\t\t// this regex ignores A-F because it's compared against an already lowercased string\n\t\t\tre: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt( execResult[ 1 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 2 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 3 ], 16 ),\n\t\t\t\t\texecResult[ 4 ] ?\n\t\t\t\t\t\t( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) :\n\t\t\t\t\t\t1\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\n\t\t\t// this regex ignores A-F because it's compared against an already lowercased string\n\t\t\tre: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/,\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),\n\t\t\t\t\tparseInt( execResult[ 3 ] + execResult[ 3 ], 16 ),\n\t\t\t\t\texecResult[ 4 ] ?\n\t\t\t\t\t\t( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 )\n\t\t\t\t\t\t\t.toFixed( 2 ) :\n\t\t\t\t\t\t1\n\t\t\t\t];\n\t\t\t}\n\t\t}, {\n\t\t\tre: /hsla?\\(\\s*(\\d+(?:\\.\\d+)?)\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*,\\s*(\\d+(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d?(?:\\.\\d+)?)\\s*)?\\)/,\n\t\t\tspace: \"hsla\",\n\t\t\tparse: function( execResult ) {\n\t\t\t\treturn [\n\t\t\t\t\texecResult[ 1 ],\n\t\t\t\t\texecResult[ 2 ] / 100,\n\t\t\t\t\texecResult[ 3 ] / 100,\n\t\t\t\t\texecResult[ 4 ]\n\t\t\t\t];\n\t\t\t}\n\t\t} ],\n\n\t// jQuery.Color( )\n\tcolor = jQuery.Color = function( color, green, blue, alpha ) {\n\t\treturn new jQuery.Color.fn.parse( color, green, blue, alpha );\n\t},\n\tspaces = {\n\t\trgba: {\n\t\t\tprops: {\n\t\t\t\tred: {\n\t\t\t\t\tidx: 0,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t},\n\t\t\t\tgreen: {\n\t\t\t\t\tidx: 1,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t},\n\t\t\t\tblue: {\n\t\t\t\t\tidx: 2,\n\t\t\t\t\ttype: \"byte\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\thsla: {\n\t\t\tprops: {\n\t\t\t\thue: {\n\t\t\t\t\tidx: 0,\n\t\t\t\t\ttype: \"degrees\"\n\t\t\t\t},\n\t\t\t\tsaturation: {\n\t\t\t\t\tidx: 1,\n\t\t\t\t\ttype: \"percent\"\n\t\t\t\t},\n\t\t\t\tlightness: {\n\t\t\t\t\tidx: 2,\n\t\t\t\t\ttype: \"percent\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\tpropTypes = {\n\t\t\"byte\": {\n\t\t\tfloor: true,\n\t\t\tmax: 255\n\t\t},\n\t\t\"percent\": {\n\t\t\tmax: 1\n\t\t},\n\t\t\"degrees\": {\n\t\t\tmod: 360,\n\t\t\tfloor: true\n\t\t}\n\t},\n\tsupport = color.support = {},\n\n\t// element for support tests\n\tsupportElem = jQuery( \"<p>\" )[ 0 ],\n\n\t// colors = jQuery.Color.names\n\tcolors,\n\n\t// local aliases of functions called often\n\teach = jQuery.each;\n\n// determine rgba support immediately\nsupportElem.style.cssText = \"background-color:rgba(1,1,1,.5)\";\nsupport.rgba = supportElem.style.backgroundColor.indexOf( \"rgba\" ) > -1;\n\n// define cache name and alpha properties\n// for rgba and hsla spaces\neach( spaces, function( spaceName, space ) {\n\tspace.cache = \"_\" + spaceName;\n\tspace.props.alpha = {\n\t\tidx: 3,\n\t\ttype: \"percent\",\n\t\tdef: 1\n\t};\n} );\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction getType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\treturn typeof obj === \"object\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n\nfunction clamp( value, prop, allowEmpty ) {\n\tvar type = propTypes[ prop.type ] || {};\n\n\tif ( value == null ) {\n\t\treturn ( allowEmpty || !prop.def ) ? null : prop.def;\n\t}\n\n\t// ~~ is an short way of doing floor for positive numbers\n\tvalue = type.floor ? ~~value : parseFloat( value );\n\n\t// IE will pass in empty strings as value for alpha,\n\t// which will hit this case\n\tif ( isNaN( value ) ) {\n\t\treturn prop.def;\n\t}\n\n\tif ( type.mod ) {\n\n\t\t// we add mod before modding to make sure that negatives values\n\t\t// get converted properly: -10 -> 350\n\t\treturn ( value + type.mod ) % type.mod;\n\t}\n\n\t// for now all property types without mod have min and max\n\treturn Math.min( type.max, Math.max( 0, value ) );\n}\n\nfunction stringParse( string ) {\n\tvar inst = color(),\n\t\trgba = inst._rgba = [];\n\n\tstring = string.toLowerCase();\n\n\teach( stringParsers, function( _i, parser ) {\n\t\tvar parsed,\n\t\t\tmatch = parser.re.exec( string ),\n\t\t\tvalues = match && parser.parse( match ),\n\t\t\tspaceName = parser.space || \"rgba\";\n\n\t\tif ( values ) {\n\t\t\tparsed = inst[ spaceName ]( values );\n\n\t\t\t// if this was an rgba parse the assignment might happen twice\n\t\t\t// oh well....\n\t\t\tinst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];\n\t\t\trgba = inst._rgba = parsed._rgba;\n\n\t\t\t// exit each( stringParsers ) here because we matched\n\t\t\treturn false;\n\t\t}\n\t} );\n\n\t// Found a stringParser that handled it\n\tif ( rgba.length ) {\n\n\t\t// if this came from a parsed string, force \"transparent\" when alpha is 0\n\t\t// chrome, (and maybe others) return \"transparent\" as rgba(0,0,0,0)\n\t\tif ( rgba.join() === \"0,0,0,0\" ) {\n\t\t\tjQuery.extend( rgba, colors.transparent );\n\t\t}\n\t\treturn inst;\n\t}\n\n\t// named colors\n\treturn colors[ string ];\n}\n\ncolor.fn = jQuery.extend( color.prototype, {\n\tparse: function( red, green, blue, alpha ) {\n\t\tif ( red === undefined ) {\n\t\t\tthis._rgba = [ null, null, null, null ];\n\t\t\treturn this;\n\t\t}\n\t\tif ( red.jquery || red.nodeType ) {\n\t\t\tred = jQuery( red ).css( green );\n\t\t\tgreen = undefined;\n\t\t}\n\n\t\tvar inst = this,\n\t\t\ttype = getType( red ),\n\t\t\trgba = this._rgba = [];\n\n\t\t// more than 1 argument specified - assume ( red, green, blue, alpha )\n\t\tif ( green !== undefined ) {\n\t\t\tred = [ red, green, blue, alpha ];\n\t\t\ttype = \"array\";\n\t\t}\n\n\t\tif ( type === \"string\" ) {\n\t\t\treturn this.parse( stringParse( red ) || colors._default );\n\t\t}\n\n\t\tif ( type === \"array\" ) {\n\t\t\teach( spaces.rgba.props, function( _key, prop ) {\n\t\t\t\trgba[ prop.idx ] = clamp( red[ prop.idx ], prop );\n\t\t\t} );\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( type === \"object\" ) {\n\t\t\tif ( red instanceof color ) {\n\t\t\t\teach( spaces, function( _spaceName, space ) {\n\t\t\t\t\tif ( red[ space.cache ] ) {\n\t\t\t\t\t\tinst[ space.cache ] = red[ space.cache ].slice();\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\teach( spaces, function( _spaceName, space ) {\n\t\t\t\t\tvar cache = space.cache;\n\t\t\t\t\teach( space.props, function( key, prop ) {\n\n\t\t\t\t\t\t// if the cache doesn't exist, and we know how to convert\n\t\t\t\t\t\tif ( !inst[ cache ] && space.to ) {\n\n\t\t\t\t\t\t\t// if the value was null, we don't need to copy it\n\t\t\t\t\t\t\t// if the key was alpha, we don't need to copy it either\n\t\t\t\t\t\t\tif ( key === \"alpha\" || red[ key ] == null ) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinst[ cache ] = space.to( inst._rgba );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// this is the only case where we allow nulls for ALL properties.\n\t\t\t\t\t\t// call clamp with alwaysAllowEmpty\n\t\t\t\t\t\tinst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// everything defined but alpha?\n\t\t\t\t\tif ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {\n\n\t\t\t\t\t\t// use the default of 1\n\t\t\t\t\t\tif ( inst[ cache ][ 3 ] == null ) {\n\t\t\t\t\t\t\tinst[ cache ][ 3 ] = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( space.from ) {\n\t\t\t\t\t\t\tinst._rgba = space.from( inst[ cache ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t},\n\tis: function( compare ) {\n\t\tvar is = color( compare ),\n\t\t\tsame = true,\n\t\t\tinst = this;\n\n\t\teach( spaces, function( _, space ) {\n\t\t\tvar localCache,\n\t\t\t\tisCache = is[ space.cache ];\n\t\t\tif ( isCache ) {\n\t\t\t\tlocalCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];\n\t\t\t\teach( space.props, function( _, prop ) {\n\t\t\t\t\tif ( isCache[ prop.idx ] != null ) {\n\t\t\t\t\t\tsame = ( isCache[ prop.idx ] === localCache[ prop.idx ] );\n\t\t\t\t\t\treturn same;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn same;\n\t\t} );\n\t\treturn same;\n\t},\n\t_space: function() {\n\t\tvar used = [],\n\t\t\tinst = this;\n\t\teach( spaces, function( spaceName, space ) {\n\t\t\tif ( inst[ space.cache ] ) {\n\t\t\t\tused.push( spaceName );\n\t\t\t}\n\t\t} );\n\t\treturn used.pop();\n\t},\n\ttransition: function( other, distance ) {\n\t\tvar end = color( other ),\n\t\t\tspaceName = end._space(),\n\t\t\tspace = spaces[ spaceName ],\n\t\t\tstartColor = this.alpha() === 0 ? color( \"transparent\" ) : this,\n\t\t\tstart = startColor[ space.cache ] || space.to( startColor._rgba ),\n\t\t\tresult = start.slice();\n\n\t\tend = end[ space.cache ];\n\t\teach( space.props, function( _key, prop ) {\n\t\t\tvar index = prop.idx,\n\t\t\t\tstartValue = start[ index ],\n\t\t\t\tendValue = end[ index ],\n\t\t\t\ttype = propTypes[ prop.type ] || {};\n\n\t\t\t// if null, don't override start value\n\t\t\tif ( endValue === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// if null - use end\n\t\t\tif ( startValue === null ) {\n\t\t\t\tresult[ index ] = endValue;\n\t\t\t} else {\n\t\t\t\tif ( type.mod ) {\n\t\t\t\t\tif ( endValue - startValue > type.mod / 2 ) {\n\t\t\t\t\t\tstartValue += type.mod;\n\t\t\t\t\t} else if ( startValue - endValue > type.mod / 2 ) {\n\t\t\t\t\t\tstartValue -= type.mod;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );\n\t\t\t}\n\t\t} );\n\t\treturn this[ spaceName ]( result );\n\t},\n\tblend: function( opaque ) {\n\n\t\t// if we are already opaque - return ourself\n\t\tif ( this._rgba[ 3 ] === 1 ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar rgb = this._rgba.slice(),\n\t\t\ta = rgb.pop(),\n\t\t\tblend = color( opaque )._rgba;\n\n\t\treturn color( jQuery.map( rgb, function( v, i ) {\n\t\t\treturn ( 1 - a ) * blend[ i ] + a * v;\n\t\t} ) );\n\t},\n\ttoRgbaString: function() {\n\t\tvar prefix = \"rgba(\",\n\t\t\trgba = jQuery.map( this._rgba, function( v, i ) {\n\t\t\t\tif ( v != null ) {\n\t\t\t\t\treturn v;\n\t\t\t\t}\n\t\t\t\treturn i > 2 ? 1 : 0;\n\t\t\t} );\n\n\t\tif ( rgba[ 3 ] === 1 ) {\n\t\t\trgba.pop();\n\t\t\tprefix = \"rgb(\";\n\t\t}\n\n\t\treturn prefix + rgba.join() + \")\";\n\t},\n\ttoHslaString: function() {\n\t\tvar prefix = \"hsla(\",\n\t\t\thsla = jQuery.map( this.hsla(), function( v, i ) {\n\t\t\t\tif ( v == null ) {\n\t\t\t\t\tv = i > 2 ? 1 : 0;\n\t\t\t\t}\n\n\t\t\t\t// catch 1 and 2\n\t\t\t\tif ( i && i < 3 ) {\n\t\t\t\t\tv = Math.round( v * 100 ) + \"%\";\n\t\t\t\t}\n\t\t\t\treturn v;\n\t\t\t} );\n\n\t\tif ( hsla[ 3 ] === 1 ) {\n\t\t\thsla.pop();\n\t\t\tprefix = \"hsl(\";\n\t\t}\n\t\treturn prefix + hsla.join() + \")\";\n\t},\n\ttoHexString: function( includeAlpha ) {\n\t\tvar rgba = this._rgba.slice(),\n\t\t\talpha = rgba.pop();\n\n\t\tif ( includeAlpha ) {\n\t\t\trgba.push( ~~( alpha * 255 ) );\n\t\t}\n\n\t\treturn \"#\" + jQuery.map( rgba, function( v ) {\n\n\t\t\t// default to 0 when nulls exist\n\t\t\tv = ( v || 0 ).toString( 16 );\n\t\t\treturn v.length === 1 ? \"0\" + v : v;\n\t\t} ).join( \"\" );\n\t},\n\ttoString: function() {\n\t\treturn this._rgba[ 3 ] === 0 ? \"transparent\" : this.toRgbaString();\n\t}\n} );\ncolor.fn.parse.prototype = color.fn;\n\n// hsla conversions adapted from:\n// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021\n\nfunction hue2rgb( p, q, h ) {\n\th = ( h + 1 ) % 1;\n\tif ( h * 6 < 1 ) {\n\t\treturn p + ( q - p ) * h * 6;\n\t}\n\tif ( h * 2 < 1 ) {\n\t\treturn q;\n\t}\n\tif ( h * 3 < 2 ) {\n\t\treturn p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;\n\t}\n\treturn p;\n}\n\nspaces.hsla.to = function( rgba ) {\n\tif ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {\n\t\treturn [ null, null, null, rgba[ 3 ] ];\n\t}\n\tvar r = rgba[ 0 ] / 255,\n\t\tg = rgba[ 1 ] / 255,\n\t\tb = rgba[ 2 ] / 255,\n\t\ta = rgba[ 3 ],\n\t\tmax = Math.max( r, g, b ),\n\t\tmin = Math.min( r, g, b ),\n\t\tdiff = max - min,\n\t\tadd = max + min,\n\t\tl = add * 0.5,\n\t\th, s;\n\n\tif ( min === max ) {\n\t\th = 0;\n\t} else if ( r === max ) {\n\t\th = ( 60 * ( g - b ) / diff ) + 360;\n\t} else if ( g === max ) {\n\t\th = ( 60 * ( b - r ) / diff ) + 120;\n\t} else {\n\t\th = ( 60 * ( r - g ) / diff ) + 240;\n\t}\n\n\t// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%\n\t// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)\n\tif ( diff === 0 ) {\n\t\ts = 0;\n\t} else if ( l <= 0.5 ) {\n\t\ts = diff / add;\n\t} else {\n\t\ts = diff / ( 2 - add );\n\t}\n\treturn [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];\n};\n\nspaces.hsla.from = function( hsla ) {\n\tif ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {\n\t\treturn [ null, null, null, hsla[ 3 ] ];\n\t}\n\tvar h = hsla[ 0 ] / 360,\n\t\ts = hsla[ 1 ],\n\t\tl = hsla[ 2 ],\n\t\ta = hsla[ 3 ],\n\t\tq = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,\n\t\tp = 2 * l - q;\n\n\treturn [\n\t\tMath.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),\n\t\tMath.round( hue2rgb( p, q, h ) * 255 ),\n\t\tMath.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),\n\t\ta\n\t];\n};\n\n\neach( spaces, function( spaceName, space ) {\n\tvar props = space.props,\n\t\tcache = space.cache,\n\t\tto = space.to,\n\t\tfrom = space.from;\n\n\t// makes rgba() and hsla()\n\tcolor.fn[ spaceName ] = function( value ) {\n\n\t\t// generate a cache for this space if it doesn't exist\n\t\tif ( to && !this[ cache ] ) {\n\t\t\tthis[ cache ] = to( this._rgba );\n\t\t}\n\t\tif ( value === undefined ) {\n\t\t\treturn this[ cache ].slice();\n\t\t}\n\n\t\tvar ret,\n\t\t\ttype = getType( value ),\n\t\t\tarr = ( type === \"array\" || type === \"object\" ) ? value : arguments,\n\t\t\tlocal = this[ cache ].slice();\n\n\t\teach( props, function( key, prop ) {\n\t\t\tvar val = arr[ type === \"object\" ? key : prop.idx ];\n\t\t\tif ( val == null ) {\n\t\t\t\tval = local[ prop.idx ];\n\t\t\t}\n\t\t\tlocal[ prop.idx ] = clamp( val, prop );\n\t\t} );\n\n\t\tif ( from ) {\n\t\t\tret = color( from( local ) );\n\t\t\tret[ cache ] = local;\n\t\t\treturn ret;\n\t\t} else {\n\t\t\treturn color( local );\n\t\t}\n\t};\n\n\t// makes red() green() blue() alpha() hue() saturation() lightness()\n\teach( props, function( key, prop ) {\n\n\t\t// alpha is included in more than one space\n\t\tif ( color.fn[ key ] ) {\n\t\t\treturn;\n\t\t}\n\t\tcolor.fn[ key ] = function( value ) {\n\t\t\tvar local, cur, match, fn,\n\t\t\t\tvtype = getType( value );\n\n\t\t\tif ( key === \"alpha\" ) {\n\t\t\t\tfn = this._hsla ? \"hsla\" : \"rgba\";\n\t\t\t} else {\n\t\t\t\tfn = spaceName;\n\t\t\t}\n\t\t\tlocal = this[ fn ]();\n\t\t\tcur = local[ prop.idx ];\n\n\t\t\tif ( vtype === \"undefined\" ) {\n\t\t\t\treturn cur;\n\t\t\t}\n\n\t\t\tif ( vtype === \"function\" ) {\n\t\t\t\tvalue = value.call( this, cur );\n\t\t\t\tvtype = getType( value );\n\t\t\t}\n\t\t\tif ( value == null && prop.empty ) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif ( vtype === \"string\" ) {\n\t\t\t\tmatch = rplusequals.exec( value );\n\t\t\t\tif ( match ) {\n\t\t\t\t\tvalue = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === \"+\" ? 1 : -1 );\n\t\t\t\t}\n\t\t\t}\n\t\t\tlocal[ prop.idx ] = value;\n\t\t\treturn this[ fn ]( local );\n\t\t};\n\t} );\n} );\n\n// add cssHook and .fx.step function for each named hook.\n// accept a space separated string of properties\ncolor.hook = function( hook ) {\n\tvar hooks = hook.split( \" \" );\n\teach( hooks, function( _i, hook ) {\n\t\tjQuery.cssHooks[ hook ] = {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar parsed, curElem,\n\t\t\t\t\tbackgroundColor = \"\";\n\n\t\t\t\tif ( value !== \"transparent\" && ( getType( value ) !== \"string\" || ( parsed = stringParse( value ) ) ) ) {\n\t\t\t\t\tvalue = color( parsed || value );\n\t\t\t\t\tif ( !support.rgba && value._rgba[ 3 ] !== 1 ) {\n\t\t\t\t\t\tcurElem = hook === \"backgroundColor\" ? elem.parentNode : elem;\n\t\t\t\t\t\twhile (\n\t\t\t\t\t\t\t( backgroundColor === \"\" || backgroundColor === \"transparent\" ) &&\n\t\t\t\t\t\t\tcurElem && curElem.style\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tbackgroundColor = jQuery.css( curElem, \"backgroundColor\" );\n\t\t\t\t\t\t\t\tcurElem = curElem.parentNode;\n\t\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvalue = value.blend( backgroundColor && backgroundColor !== \"transparent\" ?\n\t\t\t\t\t\t\tbackgroundColor :\n\t\t\t\t\t\t\t\"_default\" );\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue = value.toRgbaString();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\telem.style[ hook ] = value;\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// wrapped to prevent IE from throwing errors on \"invalid\" values like 'auto' or 'inherit'\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tjQuery.fx.step[ hook ] = function( fx ) {\n\t\t\tif ( !fx.colorInit ) {\n\t\t\t\tfx.start = color( fx.elem, hook );\n\t\t\t\tfx.end = color( fx.end );\n\t\t\t\tfx.colorInit = true;\n\t\t\t}\n\t\t\tjQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );\n\t\t};\n\t} );\n\n};\n\ncolor.hook( stepHooks );\n\njQuery.cssHooks.borderColor = {\n\texpand: function( value ) {\n\t\tvar expanded = {};\n\n\t\teach( [ \"Top\", \"Right\", \"Bottom\", \"Left\" ], function( _i, part ) {\n\t\t\texpanded[ \"border\" + part + \"Color\" ] = value;\n\t\t} );\n\t\treturn expanded;\n\t}\n};\n\n// Basic color names only.\n// Usage of any of the other color names requires adding yourself or including\n// jquery.color.svg-names.js.\ncolors = jQuery.Color.names = {\n\n\t// 4.1. Basic color keywords\n\taqua: \"#00ffff\",\n\tblack: \"#000000\",\n\tblue: \"#0000ff\",\n\tfuchsia: \"#ff00ff\",\n\tgray: \"#808080\",\n\tgreen: \"#008000\",\n\tlime: \"#00ff00\",\n\tmaroon: \"#800000\",\n\tnavy: \"#000080\",\n\tolive: \"#808000\",\n\tpurple: \"#800080\",\n\tred: \"#ff0000\",\n\tsilver: \"#c0c0c0\",\n\tteal: \"#008080\",\n\twhite: \"#ffffff\",\n\tyellow: \"#ffff00\",\n\n\t// 4.2.3. \"transparent\" color keyword\n\ttransparent: [ null, null, null, 0 ],\n\n\t_default: \"#ffffff\"\n};\n\n} );\n","jquery/bootstrap/collapse.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): collapse.js and base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([\n    \"jquery\",\n    \"./util/index\",\n    \"./dom/data\",\n    \"./dom/event-handler\",\n    \"./dom/manipulator\",\n    \"./dom/selector-engine\"\n], function($, Util, Data, EventHandler, Manipulator, SelectorEngine) {\n    'use strict';\n\n    const defineJQueryPlugin = Util.defineJQueryPlugin;\n    const executeAfterTransition = Util.executeAfterTransition;\n    const getElement = Util.getElement;\n    const getSelectorFromElement = Util.getSelectorFromElement;\n    const getElementFromSelector = Util.getElementFromSelector;\n    const reflow = Util.reflow;\n    const typeCheckConfig = Util.typeCheckConfig;\n\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n\n    const VERSION = '5.1.3';\n    const NAME = 'collapse';\n    const DATA_KEY = 'bs.collapse';\n    const EVENT_KEY = `.${DATA_KEY}`;\n    const DATA_API_KEY = '.data-api';\n\n    const Default = {\n        toggle: true,\n        parent: null\n    };\n\n    const DefaultType = {\n        toggle: 'boolean',\n        parent: '(null|element)'\n    };\n\n    const EVENT_SHOW = `show${EVENT_KEY}`;\n    const EVENT_SHOWN = `shown${EVENT_KEY}`;\n    const EVENT_HIDE = `hide${EVENT_KEY}`;\n    const EVENT_HIDDEN = `hidden${EVENT_KEY}`;\n    const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;\n\n    const CLASS_NAME_SHOW = 'show';\n    const CLASS_NAME_COLLAPSE = 'collapse';\n    const CLASS_NAME_COLLAPSING = 'collapsing';\n    const CLASS_NAME_COLLAPSED = 'collapsed';\n    const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;\n    const CLASS_NAME_HORIZONTAL = 'collapse-horizontal';\n\n    const WIDTH = 'width';\n    const HEIGHT = 'height';\n\n    const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';\n    const SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]';\n\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n    var Collapse = function(element, config) {\n        element = getElement(element);\n\n        if (!element) {\n            return;\n        }\n\n        this._element = element;\n        Data.set(this._element, DATA_KEY, this);\n\n        this._isTransitioning = false;\n        this._config = this._getConfig(config);\n        this._triggerArray = [];\n\n        const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE);\n\n        for (let i = 0, len = toggleList.length; i < len; i++) {\n            const elem = toggleList[i];\n            const selector = getSelectorFromElement(elem);\n            const filterElement = SelectorEngine.find(selector)\n                .filter(foundElem => foundElem === this._element);\n\n            if (selector !== null && filterElement.length) {\n                this._selector = selector;\n                this._triggerArray.push(elem);\n            }\n        }\n\n        this._initializeChildren();\n\n        if (!this._config.parent) {\n            this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());\n        }\n\n        if (this._config.toggle) {\n            this.toggle();\n        }\n    }\n\n    // Getters\n\n    Collapse.VERSION = VERSION;\n\n    Collapse.Default = Default;\n\n    Collapse.NAME = NAME;\n\n    Collapse.DATA_KEY = 'bs.' + Collapse.NAME;\n\n    Collapse.EVENT_KEY = '.' + Collapse.DATA_KEY;\n\n    // Public\n\n    Collapse.prototype.dispose = function() {\n        Data.remove(this._element, this.constructor.DATA_KEY);\n        EventHandler.off(this._element, this.constructor.EVENT_KEY);\n\n        Object.getOwnPropertyNames(this).forEach(propertyName => {\n            this[propertyName] = null;\n        })\n    }\n\n    Collapse.prototype._queueCallback = function(callback, element, isAnimated = true) {\n        executeAfterTransition(callback, element, isAnimated);\n    }\n\n    Collapse.prototype.toggle = function() {\n        if (this._isShown()) {\n            this.hide();\n        } else {\n            this.show();\n        }\n    }\n\n    Collapse.prototype.show = function() {\n        if (this._isTransitioning || this._isShown()) {\n            return;\n        }\n\n        let actives = [];\n        let activesData;\n\n        if (this._config.parent) {\n            const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);\n            actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)); // remove children if greater depth\n        }\n\n        const container = SelectorEngine.findOne(this._selector);\n        if (actives.length) {\n            const tempActiveData = actives.find(elem => container !== elem);\n            activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null;\n\n            if (activesData && activesData._isTransitioning) {\n                return;\n            }\n        }\n\n        const startEvent = EventHandler.trigger(this._element, EVENT_SHOW);\n        if (startEvent.defaultPrevented) {\n            return;\n        }\n\n        actives.forEach(elemActive => {\n            if (container !== elemActive) {\n                Collapse.getOrCreateInstance(elemActive, {toggle: false}).hide();\n            }\n\n            if (!activesData) {\n                Data.set(elemActive, DATA_KEY, null);\n            }\n        })\n\n        const dimension = this._getDimension();\n\n        this._element.classList.remove(CLASS_NAME_COLLAPSE);\n        this._element.classList.add(CLASS_NAME_COLLAPSING);\n\n        this._element.style[dimension] = 0;\n\n        this._addAriaAndCollapsedClass(this._triggerArray, true);\n        this._isTransitioning = true;\n\n        const complete = () => {\n            this._isTransitioning = false;\n\n            this._element.classList.remove(CLASS_NAME_COLLAPSING);\n            this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);\n\n            this._element.style[dimension] = '';\n\n            EventHandler.trigger(this._element, EVENT_SHOWN);\n        };\n\n        const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n        const scrollSize = `scroll${capitalizedDimension}`;\n\n        this._queueCallback(complete, this._element, true);\n        this._element.style[dimension] = `${this._element[scrollSize]}px`;\n    }\n\n    Collapse.prototype.hide = function() {\n        if (this._isTransitioning || !this._isShown()) {\n            return;\n        }\n\n        const startEvent = EventHandler.trigger(this._element, EVENT_HIDE);\n        if (startEvent.defaultPrevented) {\n            return;\n        }\n\n        const dimension = this._getDimension();\n\n        this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;\n\n        reflow(this._element);\n\n        this._element.classList.add(CLASS_NAME_COLLAPSING);\n        this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);\n\n        const triggerArrayLength = this._triggerArray.length;\n        for (let i = 0; i < triggerArrayLength; i++) {\n            const trigger = this._triggerArray[i];\n            const elem = getElementFromSelector(trigger);\n\n            if (elem && !this._isShown(elem)) {\n                this._addAriaAndCollapsedClass([trigger], false);\n            }\n        }\n\n        this._isTransitioning = true;\n\n        const complete = () => {\n            this._isTransitioning = false;\n            this._element.classList.remove(CLASS_NAME_COLLAPSING);\n            this._element.classList.add(CLASS_NAME_COLLAPSE);\n            EventHandler.trigger(this._element, EVENT_HIDDEN);\n        };\n\n        this._element.style[dimension] = '';\n\n        this._queueCallback(complete, this._element, true);\n    }\n\n    Collapse.prototype._isShown = function(element = this._element) {\n        return element.classList.contains(CLASS_NAME_SHOW);\n    }\n\n    // Private\n\n    Collapse.prototype._getConfig = function(config) {\n        config = {\n            ...Default,\n            ...Manipulator.getDataAttributes(this._element),\n            ...config\n        };\n        config.toggle = Boolean(config.toggle); // Coerce string values\n        config.parent = getElement(config.parent);\n        typeCheckConfig(NAME, config, DefaultType);\n        return config;\n    }\n\n    Collapse.prototype._getDimension = function() {\n        return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;\n    }\n\n    Collapse.prototype._initializeChildren = function() {\n        if (!this._config.parent) {\n            return;\n        }\n\n        const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);\n        SelectorEngine.find(SELECTOR_DATA_TOGGLE, this._config.parent).filter(elem => !children.includes(elem))\n            .forEach(element => {\n                const selected = getElementFromSelector(element);\n\n                if (selected) {\n                    this._addAriaAndCollapsedClass([element], this._isShown(selected));\n                }\n            })\n    }\n\n    Collapse.prototype._addAriaAndCollapsedClass = function(triggerArray, isOpen) {\n        if (!triggerArray.length) {\n            return;\n        }\n\n        triggerArray.forEach(elem => {\n            if (isOpen) {\n                elem.classList.remove(CLASS_NAME_COLLAPSED);\n            } else {\n                elem.classList.add(CLASS_NAME_COLLAPSED);\n            }\n\n            elem.setAttribute('aria-expanded', isOpen);\n        })\n    }\n\n    // Static\n\n    Collapse.getInstance = function(element) {\n        return Data.get(getElement(element), this.DATA_KEY);\n    }\n\n    Collapse.getOrCreateInstance = function(element, config = {}) {\n        return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n    }\n\n    Collapse.jQueryInterface = function(config) {\n        return this.each(function () {\n            const _config = {};\n            if (typeof config === 'string' && /show|hide/.test(config)) {\n                _config.toggle = false;\n            }\n\n            const data = Collapse.getOrCreateInstance(this, _config);\n\n            if (typeof config === 'string') {\n                if (typeof data[config] === 'undefined') {\n                    throw new TypeError(`No method named \"${config}\"`);\n                }\n\n                data[config]();\n            }\n        })\n    }\n\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n    EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n        // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n        if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n            event.preventDefault();\n        }\n\n        const selector = getSelectorFromElement(this);\n        const selectorElements = SelectorEngine.find(selector);\n\n        selectorElements.forEach(element => {\n            Collapse.getOrCreateInstance(element, {toggle: false}).toggle();\n        })\n    })\n\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     * add .Collapse to jQuery only if jQuery is present\n     */\n\n    defineJQueryPlugin(Collapse);\n\n    return Collapse;\n});\n","jquery/bootstrap/tab.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tab.js and base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([\n    \"./util/index\",\n    \"./dom/event-handler\",\n    \"./dom/selector-engine\"\n], function(Util, EventHandler, SelectorEngine) {\n    'use strict';\n\n    const defineJQueryPlugin = Util.defineJQueryPlugin;\n    const executeAfterTransition = Util.executeAfterTransition;\n    const getElement = Util.getElement;\n    const getElementFromSelector = Util.getElementFromSelector;\n    const isDisabled = Util.isDisabled;\n    const reflow = Util.reflow;\n\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n\n    const VERSION = '5.1.3';\n    const NAME = 'tab';\n    const DATA_KEY = 'bs.tab';\n    const EVENT_KEY = `.${DATA_KEY}`;\n    const DATA_API_KEY = '.data-api';\n\n    const EVENT_HIDE = `hide${EVENT_KEY}`;\n    const EVENT_HIDDEN = `hidden${EVENT_KEY}`;\n    const EVENT_SHOW = `show${EVENT_KEY}`;\n    const EVENT_SHOWN = `shown${EVENT_KEY}`;\n    const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;\n\n    const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';\n    const CLASS_NAME_ACTIVE = 'active';\n    const CLASS_NAME_FADE = 'fade';\n    const CLASS_NAME_SHOW = 'show';\n\n    const SELECTOR_DROPDOWN = '.dropdown';\n    const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\n    const SELECTOR_ACTIVE = '.active';\n    const SELECTOR_ACTIVE_UL = ':scope > li > .active';\n    const SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]';\n    const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';\n    const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active';\n\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n    function Tab(element) {\n        element = getElement(element);\n\n        if (!element) {\n            return;\n        }\n\n        this._element = element;\n        Data.set(this._element, DATA_KEY, this);\n    }\n\n    // Getters\n\n    Tab.VERSION = VERSION;\n\n    Tab.NAME = NAME;\n\n    Tab.DATA_KEY = 'bs.' + Tab.NAME;\n\n    Tab.EVENT_KEY = '.' + Tab.DATA_KEY;\n\n    // Public\n\n    Tab.prototype.dispose = function() {\n        Data.remove(this._element, this.constructor.DATA_KEY);\n        EventHandler.off(this._element, this.constructor.EVENT_KEY);\n\n        Object.getOwnPropertyNames(this).forEach(propertyName => {\n            this[propertyName] = null;\n        })\n    }\n\n    Tab.prototype._queueCallback = function(callback, element, isAnimated = true) {\n        executeAfterTransition(callback, element, isAnimated);\n    }\n\n    Tab.prototype.show = function() {\n        if ((this._element.parentNode &&\n            this._element.parentNode.nodeType === Node.ELEMENT_NODE &&\n            this._element.classList.contains(CLASS_NAME_ACTIVE))) {\n            return;\n        }\n\n        let previous;\n        const target = getElementFromSelector(this._element);\n        const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP);\n\n        if (listElement) {\n            const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE;\n            previous = SelectorEngine.find(itemSelector, listElement);\n            previous = previous[previous.length - 1];\n        }\n\n        const hideEvent = previous ?\n            EventHandler.trigger(previous, EVENT_HIDE, {\n                relatedTarget: this._element\n            }) :\n            null;\n\n        const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n            relatedTarget: previous\n        });\n\n        if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {\n            return;\n        }\n\n        this._activate(this._element, listElement);\n\n        const complete = () => {\n            EventHandler.trigger(previous, EVENT_HIDDEN, {\n                relatedTarget: this._element\n            });\n            EventHandler.trigger(this._element, EVENT_SHOWN, {\n                relatedTarget: previous\n            });\n        };\n\n        if (target) {\n            this._activate(target, target.parentNode, complete);\n        } else {\n            complete();\n        }\n    }\n\n    // Private\n\n    Tab.prototype._activate = function(element, container, callback) {\n        const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?\n            SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :\n            SelectorEngine.children(container, SELECTOR_ACTIVE);\n\n        const active = activeElements[0];\n        const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE));\n\n        const complete = () => this._transitionComplete(element, active, callback);\n\n        if (active && isTransitioning) {\n            active.classList.remove(CLASS_NAME_SHOW);\n            this._queueCallback(complete, element, true);\n        } else {\n            complete();\n        }\n    }\n\n    Tab.prototype._transitionComplete = function(element, active, callback) {\n        if (active) {\n            active.classList.remove(CLASS_NAME_ACTIVE);\n\n            const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode);\n\n            if (dropdownChild) {\n                dropdownChild.classList.remove(CLASS_NAME_ACTIVE);\n            }\n\n            if (active.getAttribute('role') === 'tab') {\n                active.setAttribute('aria-selected', false);\n            }\n        }\n\n        element.classList.add(CLASS_NAME_ACTIVE);\n        if (element.getAttribute('role') === 'tab') {\n            element.setAttribute('aria-selected', true);\n        }\n\n        reflow(element);\n\n        if (element.classList.contains(CLASS_NAME_FADE)) {\n            element.classList.add(CLASS_NAME_SHOW);\n        }\n\n        let parent = element.parentNode;\n        if (parent && parent.nodeName === 'LI') {\n            parent = parent.parentNode;\n        }\n\n        if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {\n            const dropdownElement = element.closest(SELECTOR_DROPDOWN);\n\n            if (dropdownElement) {\n                SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement)\n                    .forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE));\n            }\n\n            element.setAttribute('aria-expanded', true);\n        }\n\n        if (callback) {\n            callback();\n        }\n    }\n\n    // Static\n\n    Tab.getInstance = function(element) {\n        return Data.get(getElement(element), this.DATA_KEY);\n    }\n\n    Tab.getOrCreateInstance = function(element, config = {}) {\n        return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n    }\n\n    Tab.jQueryInterface = function(config) {\n        return this.each(function () {\n            const data = Tab.getOrCreateInstance(this);\n\n            if (typeof config === 'string') {\n                if (typeof data[config] === 'undefined') {\n                    throw new TypeError(`No method named \"${config}\"`);\n                }\n\n                data[config]();\n            }\n        })\n    }\n\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n    EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n        if (['A', 'AREA'].includes(this.tagName)) {\n            event.preventDefault();\n        }\n\n        if (isDisabled(this)) {\n            return;\n        }\n\n        const data = Tab.getOrCreateInstance(this);\n        data.show();\n    })\n\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     * add .Tab to jQuery only if jQuery is present\n     */\n\n    defineJQueryPlugin(Tab);\n\n    return Tab;\n});\n","jquery/bootstrap/dom/manipulator.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([], function() {\n    'use strict';\n\n    function normalizeData(val) {\n        if (val === 'true') {\n            return true\n        }\n\n        if (val === 'false') {\n            return false\n        }\n\n        if (val === Number(val).toString()) {\n            return Number(val)\n        }\n\n        if (val === '' || val === 'null') {\n            return null\n        }\n\n        return val\n    }\n\n    function normalizeDataKey(key) {\n        return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n    }\n\n    return {\n        setDataAttribute: function(element, key, value) {\n            element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n        },\n\n        removeDataAttribute: function(element, key) {\n            element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n        },\n\n        getDataAttributes: function(element) {\n            if (!element) {\n                return {}\n            }\n\n            const attributes = {};\n\n            Object.keys(element.dataset)\n                .filter(key => key.startsWith('bs'))\n                .forEach(key => {\n                    let pureKey = key.replace(/^bs/, '');\n                    pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n                    attributes[pureKey] = normalizeData(element.dataset[key])\n                })\n\n            return attributes\n        },\n\n        getDataAttribute: function(element, key) {\n            return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n        },\n\n        offset: function(element) {\n            const rect = element.getBoundingClientRect();\n\n            return {\n                top: rect.top + window.pageYOffset,\n                left: rect.left + window.pageXOffset\n            }\n        },\n\n        position: function(element) {\n            return {\n                top: element.offsetTop,\n                left: element.offsetLeft\n            }\n        }\n    }\n});\n","jquery/bootstrap/dom/data.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([], function() {\n    'use strict';\n\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n\n    const elementMap = new Map();\n\n    return {\n        set: function (element, key, instance) {\n            if (!elementMap.has(element)) {\n                elementMap.set(element, new Map())\n            }\n\n            const instanceMap = elementMap.get(element);\n\n            // make it clear we only want one instance per element\n            // can be removed later when multiple key/instances are fine to be used\n            if (!instanceMap.has(key) && instanceMap.size !== 0) {\n                // eslint-disable-next-line no-console\n                console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n                return\n            }\n\n            instanceMap.set(key, instance)\n        },\n\n        get: function (element, key) {\n            if (elementMap.has(element)) {\n                return elementMap.get(element).get(key) || null\n            }\n\n            return null\n        },\n\n        remove: function (element, key) {\n            if (!elementMap.has(element)) {\n                return\n            }\n\n            const instanceMap = elementMap.get(element);\n\n            instanceMap.delete(key)\n\n            // free up element references if there are no instances left for an element\n            if (instanceMap.size === 0) {\n                elementMap.delete(element)\n            }\n        }\n    }\n});\n","jquery/bootstrap/dom/event-handler.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([\n    \"../util/index\"\n], function(Util) {\n    'use strict';\n\n    const getjQuery = Util.getjQuery;\n\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n\n    const namespaceRegex = /[^.]*(?=\\..*)\\.|.*/;\n    const stripNameRegex = /\\..*/;\n    const stripUidRegex = /::\\d+$/;\n    const eventRegistry = {}; // Events storage\n    let uidEvent = 1;\n    const customEvents = {\n        mouseenter: 'mouseover',\n        mouseleave: 'mouseout'\n    };\n    const customEventsRegex = /^(mouseenter|mouseleave)/i;\n    const nativeEvents = new Set([\n        'click',\n        'dblclick',\n        'mouseup',\n        'mousedown',\n        'contextmenu',\n        'mousewheel',\n        'DOMMouseScroll',\n        'mouseover',\n        'mouseout',\n        'mousemove',\n        'selectstart',\n        'selectend',\n        'keydown',\n        'keypress',\n        'keyup',\n        'orientationchange',\n        'touchstart',\n        'touchmove',\n        'touchend',\n        'touchcancel',\n        'pointerdown',\n        'pointermove',\n        'pointerup',\n        'pointerleave',\n        'pointercancel',\n        'gesturestart',\n        'gesturechange',\n        'gestureend',\n        'focus',\n        'blur',\n        'change',\n        'reset',\n        'select',\n        'submit',\n        'focusin',\n        'focusout',\n        'load',\n        'unload',\n        'beforeunload',\n        'resize',\n        'move',\n        'DOMContentLoaded',\n        'readystatechange',\n        'error',\n        'abort',\n        'scroll'\n    ]);\n\n    /**\n     * ------------------------------------------------------------------------\n     * Private methods\n     * ------------------------------------------------------------------------\n     */\n\n    function getUidEvent(element, uid) {\n        return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n    }\n\n    function getEvent(element) {\n        const uid = getUidEvent(element);\n\n        element.uidEvent = uid\n        eventRegistry[uid] = eventRegistry[uid] || {}\n\n        return eventRegistry[uid]\n    }\n\n    function bootstrapHandler(element, fn) {\n        return function handler(event) {\n            event.delegateTarget = element\n\n            if (handler.oneOff) {\n                EventHandler.off(element, event.type, fn)\n            }\n\n            return fn.apply(element, [event])\n        }\n    }\n\n    function bootstrapDelegationHandler(element, selector, fn) {\n        return function handler(event) {\n            const domElements = element.querySelectorAll(selector);\n\n            for (let {target} = event; target && target !== this; target = target.parentNode) {\n                for (let i = domElements.length; i--;) {\n                    if (domElements[i] === target) {\n                        event.delegateTarget = target\n\n                        if (handler.oneOff) {\n                            EventHandler.off(element, event.type, selector, fn)\n                        }\n\n                        return fn.apply(target, [event])\n                    }\n                }\n            }\n\n            // To please ESLint\n            return null\n        }\n    }\n\n    function findHandler(events, handler, delegationSelector = null) {\n        const uidEventList = Object.keys(events);\n\n        for (let i = 0, len = uidEventList.length; i < len; i++) {\n            const event = events[uidEventList[i]];\n\n            if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {\n                return event\n            }\n        }\n\n        return null\n    }\n\n    function normalizeParams(originalTypeEvent, handler, delegationFn) {\n        const delegation = typeof handler === 'string';\n        const originalHandler = delegation ? delegationFn : handler;\n\n        let typeEvent = getTypeEvent(originalTypeEvent);\n        const isNative = nativeEvents.has(typeEvent);\n\n        if (!isNative) {\n            typeEvent = originalTypeEvent\n        }\n\n        return [delegation, originalHandler, typeEvent]\n    }\n\n    function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {\n        if (typeof originalTypeEvent !== 'string' || !element) {\n            return\n        }\n\n        if (!handler) {\n            handler = delegationFn\n            delegationFn = null\n        }\n\n        // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n        // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n        if (customEventsRegex.test(originalTypeEvent)) {\n            const wrapFn = fn => {\n                return function (event) {\n                    if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n                        return fn.call(this, event)\n                    }\n                }\n            };\n\n            if (delegationFn) {\n                delegationFn = wrapFn(delegationFn)\n            } else {\n                handler = wrapFn(handler)\n            }\n        }\n\n        const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);\n        const events = getEvent(element);\n        const handlers = events[typeEvent] || (events[typeEvent] = {});\n        const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null);\n\n        if (previousFn) {\n            previousFn.oneOff = previousFn.oneOff && oneOff\n\n            return\n        }\n\n        const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''));\n        const fn = delegation ?\n            bootstrapDelegationHandler(element, handler, delegationFn) :\n            bootstrapHandler(element, handler);\n\n        fn.delegationSelector = delegation ? handler : null\n        fn.originalHandler = originalHandler\n        fn.oneOff = oneOff\n        fn.uidEvent = uid\n        handlers[uid] = fn\n\n        element.addEventListener(typeEvent, fn, delegation)\n    }\n\n    function removeHandler(element, events, typeEvent, handler, delegationSelector) {\n        const fn = findHandler(events[typeEvent], handler, delegationSelector);\n\n        if (!fn) {\n            return\n        }\n\n        element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n        delete events[typeEvent][fn.uidEvent]\n    }\n\n    function removeNamespacedHandlers(element, events, typeEvent, namespace) {\n        const storeElementEvent = events[typeEvent] || {};\n\n        Object.keys(storeElementEvent).forEach(handlerKey => {\n            if (handlerKey.includes(namespace)) {\n                const event = storeElementEvent[handlerKey];\n\n                removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n            }\n        })\n    }\n\n    function getTypeEvent(event) {\n        // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n        event = event.replace(stripNameRegex, '')\n        return customEvents[event] || event\n    }\n\n    return {\n        on: function(element, event, handler, delegationFn) {\n            addHandler(element, event, handler, delegationFn, false)\n        },\n\n        one: function(element, event, handler, delegationFn) {\n            addHandler(element, event, handler, delegationFn, true)\n        },\n\n        off: function(element, originalTypeEvent, handler, delegationFn) {\n            if (typeof originalTypeEvent !== 'string' || !element) {\n                return\n            }\n\n            const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);\n            const inNamespace = typeEvent !== originalTypeEvent;\n            const events = getEvent(element);\n            const isNamespace = originalTypeEvent.startsWith('.');\n\n            if (typeof originalHandler !== 'undefined') {\n                // Simplest case: handler is passed, remove that listener ONLY.\n                if (!events || !events[typeEvent]) {\n                    return\n                }\n\n                removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)\n                return\n            }\n\n            if (isNamespace) {\n                Object.keys(events).forEach(elementEvent => {\n                    removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n                })\n            }\n\n            const storeElementEvent = events[typeEvent] || {};\n            Object.keys(storeElementEvent).forEach(keyHandlers => {\n                const handlerKey = keyHandlers.replace(stripUidRegex, '');\n\n                if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n                    const event = storeElementEvent[keyHandlers];\n\n                    removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n                }\n            })\n        },\n\n        trigger: function(element, event, args) {\n            if (typeof event !== 'string' || !element) {\n                return null\n            }\n\n            const $ = getjQuery();\n            const typeEvent = getTypeEvent(event);\n            const inNamespace = event !== typeEvent;\n            const isNative = nativeEvents.has(typeEvent);\n\n            let jQueryEvent;\n            let bubbles = true;\n            let nativeDispatch = true;\n            let defaultPrevented = false;\n            let evt = null;\n\n            if (inNamespace && $) {\n                jQueryEvent = $.Event(event, args)\n\n                $(element).trigger(jQueryEvent)\n                bubbles = !jQueryEvent.isPropagationStopped()\n                nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n                defaultPrevented = jQueryEvent.isDefaultPrevented()\n            }\n\n            if (isNative) {\n                evt = document.createEvent('HTMLEvents')\n                evt.initEvent(typeEvent, bubbles, true)\n            } else {\n                evt = new CustomEvent(event, {\n                    bubbles,\n                    cancelable: true\n                })\n            }\n\n            // merge custom information in our event\n            if (typeof args !== 'undefined') {\n                Object.keys(args).forEach(key => {\n                    Object.defineProperty(evt, key, {\n                        get() {\n                            return args[key]\n                        }\n                    })\n                })\n            }\n\n            if (defaultPrevented) {\n                evt.preventDefault()\n            }\n\n            if (nativeDispatch) {\n                element.dispatchEvent(evt)\n            }\n\n            if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {\n                jQueryEvent.preventDefault()\n            }\n\n            return evt\n        }\n    }\n});\n","jquery/bootstrap/dom/selector-engine.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\ndefine([\n    \"../util/index\"\n], function(Util) {\n    'use strict';\n\n    const isDisabled = Util.isDisabled;\n    const isVisible = Util.isVisible;\n\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n\n    const NODE_TEXT = 3;\n\n    return {\n        find: function(selector, element = document.documentElement) {\n            return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n        },\n\n        findOne: function(selector, element = document.documentElement) {\n            return Element.prototype.querySelector.call(element, selector)\n        },\n\n        children: function(element, selector) {\n            return [].concat(...element.children)\n                .filter(child => child.matches(selector))\n        },\n\n        parents: function(element, selector) {\n            const parents = [];\n\n            let ancestor = element.parentNode;\n\n            while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {\n                if (ancestor.matches(selector)) {\n                    parents.push(ancestor)\n                }\n\n                ancestor = ancestor.parentNode\n            }\n\n            return parents\n        },\n\n        prev: function(element, selector) {\n            let previous = element.previousElementSibling;\n\n            while (previous) {\n                if (previous.matches(selector)) {\n                    return [previous]\n                }\n\n                previous = previous.previousElementSibling\n            }\n\n            return []\n        },\n\n        next: function(element, selector) {\n            let next = element.nextElementSibling;\n\n            while (next) {\n                if (next.matches(selector)) {\n                    return [next]\n                }\n\n                next = next.nextElementSibling\n            }\n\n            return []\n        },\n\n        focusableChildren: function(element) {\n            const focusables = [\n                'a',\n                'button',\n                'input',\n                'textarea',\n                'select',\n                'details',\n                '[tabindex]',\n                '[contenteditable=\"true\"]'\n            ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(', ');\n\n            return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n        }\n    }\n});\n","jquery/bootstrap/util/index.js":"/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\ndefine([\n    \"jquery\",\n    'domReady!'\n], function() {\n    'use strict';\n\n    const MAX_UID = 1000000;\n    const MILLISECONDS_MULTIPLIER = 1000;\n    const TRANSITION_END = 'transitionend';\n\n    // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n    const toType = obj => {\n        if (obj === null || obj === undefined) {\n            return `${obj}`\n        }\n\n        return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase()\n    };\n\n    /**\n     * --------------------------------------------------------------------------\n     * Public Util Api\n     * --------------------------------------------------------------------------\n     */\n\n    const getUID = prefix => {\n        do {\n            prefix += Math.floor(Math.random() * MAX_UID)\n        } while (document.getElementById(prefix))\n\n        return prefix\n    };\n\n    const getSelector = element => {\n        let selector = element.getAttribute('data-bs-target');\n\n        if (!selector || selector === '#') {\n            let hrefAttr = element.getAttribute('href');\n\n            // The only valid content that could double as a selector are IDs or classes,\n            // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n            // `document.querySelector` will rightfully complain it is invalid.\n            // See https://github.com/twbs/bootstrap/issues/32273\n            if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {\n                return null\n            }\n\n            // Just in case some CMS puts out a full URL with the anchor appended\n            if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {\n                hrefAttr = `#${hrefAttr.split('#')[1]}`\n            }\n\n            selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null\n        }\n\n        return selector\n    };\n\n    const getSelectorFromElement = element => {\n        const selector = getSelector(element);\n\n        if (selector) {\n            return document.querySelector(selector) ? selector : null\n        }\n\n        return null\n    };\n\n    const getElementFromSelector = element => {\n        const selector = getSelector(element);\n\n        return selector ? document.querySelector(selector) : null\n    };\n\n    const getTransitionDurationFromElement = element => {\n        if (!element) {\n            return 0\n        }\n\n        // Get transition-duration of the element\n        let {transitionDuration, transitionDelay} = window.getComputedStyle(element);\n\n        const floatTransitionDuration = Number.parseFloat(transitionDuration);\n        const floatTransitionDelay = Number.parseFloat(transitionDelay);\n\n        // Return 0 if element or transition duration is not found\n        if (!floatTransitionDuration && !floatTransitionDelay) {\n            return 0\n        }\n\n        // If multiple durations are defined, take the first\n        transitionDuration = transitionDuration.split(',')[0]\n        transitionDelay = transitionDelay.split(',')[0]\n\n        return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n    };\n\n    const triggerTransitionEnd = element => {\n        element.dispatchEvent(new Event(TRANSITION_END))\n    };\n\n    const isElement = obj => {\n        if (!obj || typeof obj !== 'object') {\n            return false\n        }\n\n        if (typeof obj.jquery !== 'undefined') {\n            obj = obj[0]\n        }\n\n        return typeof obj.nodeType !== 'undefined'\n    };\n\n    const getElement = obj => {\n        if (isElement(obj)) { // it's a jQuery object or a node element\n            return obj.jquery ? obj[0] : obj\n        }\n\n        if (typeof obj === 'string' && obj.length > 0) {\n            return document.querySelector(obj)\n        }\n\n        return null\n    };\n\n    const typeCheckConfig = (componentName, config, configTypes) => {\n        Object.keys(configTypes).forEach(property => {\n            const expectedTypes = configTypes[property];\n            const value = config[property];\n            const valueType = value && isElement(value) ? 'element' : toType(value);\n\n            if (!new RegExp(expectedTypes).test(valueType)) {\n                throw new TypeError(\n                    `${componentName.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n                )\n            }\n        })\n    };\n\n    const isVisible = element => {\n        if (!isElement(element) || element.getClientRects().length === 0) {\n            return false\n        }\n\n        return getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n    };\n\n    const isDisabled = element => {\n        if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n            return true\n        }\n\n        if (element.classList.contains('disabled')) {\n            return true\n        }\n\n        if (typeof element.disabled !== 'undefined') {\n            return element.disabled\n        }\n\n        return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n    };\n\n    const findShadowRoot = element => {\n        if (!document.documentElement.attachShadow) {\n            return null\n        }\n\n        // Can find the shadow root otherwise it'll return the document\n        if (typeof element.getRootNode === 'function') {\n            const root = element.getRootNode();\n            return root instanceof ShadowRoot ? root : null\n        }\n\n        if (element instanceof ShadowRoot) {\n            return element\n        }\n\n        // when we don't find a shadow root\n        if (!element.parentNode) {\n            return null\n        }\n\n        return findShadowRoot(element.parentNode)\n    };\n\n    const noop = () => {};\n\n    /**\n     * Trick to restart an element's animation\n     *\n     * @param {HTMLElement} element\n     * @return void\n     *\n     * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n     */\n    const reflow = element => {\n        // eslint-disable-next-line no-unused-expressions\n        element.offsetHeight\n    };\n\n    const getjQuery = () => {\n        const {jQuery} = window;\n\n        if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n            return jQuery\n        }\n\n        return null\n    };\n\n    const DOMContentLoadedCallbacks = [];\n\n    const onDOMContentLoaded = callback => {\n        if (document.readyState === 'loading') {\n            // add listener on the first call when the document is in loading state\n            if (!DOMContentLoadedCallbacks.length) {\n                document.addEventListener('DOMContentLoaded', () => {\n                    DOMContentLoadedCallbacks.forEach(callback => callback())\n                })\n            }\n\n            DOMContentLoadedCallbacks.push(callback)\n        } else {\n            callback()\n        }\n    };\n\n    const isRTL = () => document.documentElement.dir === 'rtl';\n\n    const defineJQueryPlugin = plugin => {\n        onDOMContentLoaded(() => {\n            const $ = getjQuery();\n            /* istanbul ignore if */\n            if ($) {\n                const name = plugin.NAME;\n                const JQUERY_NO_CONFLICT = $.fn[name];\n                $.fn[name] = plugin.jQueryInterface\n                $.fn[name].Constructor = plugin\n                $.fn[name].noConflict = () => {\n                    $.fn[name] = JQUERY_NO_CONFLICT\n                    return plugin.jQueryInterface\n                }\n            }\n        })\n    };\n\n    const execute = callback => {\n        if (typeof callback === 'function') {\n            callback()\n        }\n    };\n\n    const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n        if (!waitForTransition) {\n            execute(callback)\n            return\n        }\n\n        const durationPadding = 5;\n        const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;\n\n        let called = false;\n\n        const handler = ({ target }) => {\n            if (target !== transitionElement) {\n                return\n            }\n\n            called = true\n            transitionElement.removeEventListener(TRANSITION_END, handler)\n            execute(callback)\n        };\n\n        transitionElement.addEventListener(TRANSITION_END, handler)\n        setTimeout(() => {\n            if (!called) {\n                triggerTransitionEnd(transitionElement)\n            }\n        }, emulatedDuration)\n    };\n\n    /**\n     * Return the previous/next element of a list.\n     *\n     * @param {array} list    The list of elements\n     * @param activeElement   The active element\n     * @param shouldGetNext   Choose to get next or previous element\n     * @param isCycleAllowed\n     * @return {Element|elem} The proper element\n     */\n    const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n        let index = list.indexOf(activeElement);\n\n        // if the element does not exist in the list return an element depending on the direction and if cycle is allowed\n        if (index === -1) {\n            return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]\n        }\n\n        const listLength = list.length;\n\n        index += shouldGetNext ? 1 : -1\n\n        if (isCycleAllowed) {\n            index = (index + listLength) % listLength\n        }\n\n        return list[Math.max(0, Math.min(index, listLength - 1))]\n    };\n\n    return {\n        getElement,\n        getUID,\n        getSelectorFromElement,\n        getElementFromSelector,\n        getTransitionDurationFromElement,\n        triggerTransitionEnd,\n        isElement,\n        typeCheckConfig,\n        isVisible,\n        isDisabled,\n        findShadowRoot,\n        noop,\n        getNextActiveElement,\n        reflow,\n        getjQuery,\n        onDOMContentLoaded,\n        isRTL,\n        defineJQueryPlugin,\n        execute,\n        executeAfterTransition\n    };\n});\n","requirejs/text.js":"/**\n * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n  define, window, process, Packages,\n  java, location, Components, FileUtils */\n\ndefine(['module'], function (module) {\n    'use strict';\n\n    var text, fs, Cc, Ci, xpcIsWindows,\n        progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n        xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n        bodyRegExp = /<body[^>]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n        hasLocation = typeof location !== 'undefined' && location.href,\n        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n        defaultHostName = hasLocation && location.hostname,\n        defaultPort = hasLocation && (location.port || undefined),\n        buildMap = {},\n        masterConfig = (module.config && module.config()) || {};\n\n    text = {\n        version: '2.0.12',\n\n        strip: function (content) {\n            //Strips <?xml ...?> declarations so that external SVG and XML\n            //documents can be added to a document without worry. Also, if the string\n            //is an HTML document, only the part inside the body tag is returned.\n            if (content) {\n                content = content.replace(xmlRegExp, \"\");\n                var matches = content.match(bodyRegExp);\n                if (matches) {\n                    content = matches[1];\n                }\n            } else {\n                content = \"\";\n            }\n            return content;\n        },\n\n        jsEscape: function (content) {\n            return content.replace(/(['\\\\])/g, '\\\\$1')\n                .replace(/[\\f]/g, \"\\\\f\")\n                .replace(/[\\b]/g, \"\\\\b\")\n                .replace(/[\\n]/g, \"\\\\n\")\n                .replace(/[\\t]/g, \"\\\\t\")\n                .replace(/[\\r]/g, \"\\\\r\")\n                .replace(/[\\u2028]/g, \"\\\\u2028\")\n                .replace(/[\\u2029]/g, \"\\\\u2029\");\n        },\n\n        createXhr: masterConfig.createXhr || function () {\n            //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n            var xhr, i, progId;\n            if (typeof XMLHttpRequest !== \"undefined\") {\n                return new XMLHttpRequest();\n            } else if (typeof ActiveXObject !== \"undefined\") {\n                for (i = 0; i < 3; i += 1) {\n                    progId = progIds[i];\n                    try {\n                        xhr = new ActiveXObject(progId);\n                    } catch (e) {}\n\n                    if (xhr) {\n                        progIds = [progId];  // so faster next time\n                        break;\n                    }\n                }\n            }\n\n            return xhr;\n        },\n\n        /**\n         * Parses a resource name into its component parts. Resource names\n         * look like: module/name.ext!strip, where the !strip part is\n         * optional.\n         * @param {String} name the resource name\n         * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n         * where strip is a boolean.\n         */\n        parseName: function (name) {\n            var modName, ext, temp,\n                strip = false,\n                index = name.indexOf(\".\"),\n                isRelative = name.indexOf('./') === 0 ||\n                             name.indexOf('../') === 0;\n\n            if (index !== -1 && (!isRelative || index > 1)) {\n                modName = name.substring(0, index);\n                ext = name.substring(index + 1, name.length);\n            } else {\n                modName = name;\n            }\n\n            temp = ext || modName;\n            index = temp.indexOf(\"!\");\n            if (index !== -1) {\n                //Pull off the strip arg.\n                strip = temp.substring(index + 1) === \"strip\";\n                temp = temp.substring(0, index);\n                if (ext) {\n                    ext = temp;\n                } else {\n                    modName = temp;\n                }\n            }\n\n            return {\n                moduleName: modName,\n                ext: ext,\n                strip: strip\n            };\n        },\n\n        xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n        /**\n         * Is an URL on another domain. Only works for browser use, returns\n         * false in non-browser environments. Only used to know if an\n         * optimized .js version of a text resource should be loaded\n         * instead.\n         * @param {String} url\n         * @returns Boolean\n         */\n        useXhr: function (url, protocol, hostname, port) {\n            var uProtocol, uHostName, uPort,\n                match = text.xdRegExp.exec(url);\n            if (!match) {\n                return true;\n            }\n            uProtocol = match[2];\n            uHostName = match[3];\n\n            uHostName = uHostName.split(':');\n            uPort = uHostName[1];\n            uHostName = uHostName[0];\n\n            return (!uProtocol || uProtocol === protocol) &&\n                   (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n                   ((!uPort && !uHostName) || uPort === port);\n        },\n\n        finishLoad: function (name, strip, content, onLoad) {\n            content = strip ? text.strip(content) : content;\n            if (masterConfig.isBuild) {\n                buildMap[name] = content;\n            }\n            onLoad(content);\n        },\n\n        load: function (name, req, onLoad, config) {\n            //Name has format: some.module.filext!strip\n            //The strip part is optional.\n            //if strip is present, then that means only get the string contents\n            //inside a body tag in an HTML string. For XML/SVG content it means\n            //removing the <?xml ...?> declarations so the content can be inserted\n            //into the current doc without problems.\n\n            // Do not bother with the work if a build and text will\n            // not be inlined.\n            if (config && config.isBuild && !config.inlineText) {\n                onLoad();\n                return;\n            }\n\n            masterConfig.isBuild = config && config.isBuild;\n\n            var parsed = text.parseName(name),\n                nonStripName = parsed.moduleName +\n                    (parsed.ext ? '.' + parsed.ext : ''),\n                url = req.toUrl(nonStripName),\n                useXhr = (masterConfig.useXhr) ||\n                         text.useXhr;\n\n            // Do not load if it is an empty: url\n            if (url.indexOf('empty:') === 0) {\n                onLoad();\n                return;\n            }\n\n            //Load the text. Use XHR if possible and in a browser.\n            if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n                text.get(url, function (content) {\n                    text.finishLoad(name, parsed.strip, content, onLoad);\n                }, function (err) {\n                    if (onLoad.error) {\n                        onLoad.error(err);\n                    }\n                });\n            } else {\n                //Need to fetch the resource across domains. Assume\n                //the resource has been optimized into a JS module. Fetch\n                //by the module name + extension, but do not include the\n                //!strip part to avoid file system issues.\n                req([nonStripName], function (content) {\n                    text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n                                    parsed.strip, content, onLoad);\n                });\n            }\n        },\n\n        write: function (pluginName, moduleName, write, config) {\n            if (buildMap.hasOwnProperty(moduleName)) {\n                var content = text.jsEscape(buildMap[moduleName]);\n                write.asModule(pluginName + \"!\" + moduleName,\n                               \"define(function () { return '\" +\n                                   content +\n                               \"';});\\n\");\n            }\n        },\n\n        writeFile: function (pluginName, moduleName, req, write, config) {\n            var parsed = text.parseName(moduleName),\n                extPart = parsed.ext ? '.' + parsed.ext : '',\n                nonStripName = parsed.moduleName + extPart,\n                //Use a '.js' file name so that it indicates it is a\n                //script that can be loaded across domains.\n                fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n            //Leverage own load() method to load plugin value, but only\n            //write out values that do not have the strip argument,\n            //to avoid any potential issues with ! in file names.\n            text.load(nonStripName, req, function (value) {\n                //Use own write() method to construct full module value.\n                //But need to create shell that translates writeFile's\n                //write() to the right interface.\n                var textWrite = function (contents) {\n                    return write(fileName, contents);\n                };\n                textWrite.asModule = function (moduleName, contents) {\n                    return write.asModule(moduleName, fileName, contents);\n                };\n\n                text.write(pluginName, nonStripName, textWrite, config);\n            }, config);\n        }\n    };\n\n    if (masterConfig.env === 'node' || (!masterConfig.env &&\n            typeof process !== \"undefined\" &&\n            process.versions &&\n            !!process.versions.node &&\n            !process.versions['node-webkit'])) {\n        //Using special require.nodeRequire, something added by r.js.\n        fs = require.nodeRequire('fs');\n\n        text.get = function (url, callback, errback) {\n            try {\n                var file = fs.readFileSync(url, 'utf8');\n                //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n                if (file.indexOf('\\uFEFF') === 0) {\n                    file = file.substring(1);\n                }\n                callback(file);\n            } catch (e) {\n                if (errback) {\n                    errback(e);\n                }\n            }\n        };\n    } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n            text.createXhr())) {\n        text.get = function (url, callback, errback, headers) {\n            var xhr = text.createXhr(), header;\n            xhr.open('GET', url, true);\n\n            //Allow plugins direct access to xhr headers\n            if (headers) {\n                for (header in headers) {\n                    if (headers.hasOwnProperty(header)) {\n                        xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n                    }\n                }\n            }\n\n            //Allow overrides specified in config\n            if (masterConfig.onXhr) {\n                masterConfig.onXhr(xhr, url);\n            }\n\n            xhr.onreadystatechange = function (evt) {\n                var status, err;\n                //Do not explicitly handle errors, those should be\n                //visible via console output in the browser.\n                if (xhr.readyState === 4) {\n                    status = xhr.status || 0;\n                    if (status > 399 && status < 600) {\n                        //An http 4xx or 5xx error. Signal an error.\n                        err = new Error(url + ' HTTP status: ' + status);\n                        err.xhr = xhr;\n                        if (errback) {\n                            errback(err);\n                        }\n                    } else {\n                        callback(xhr.responseText);\n                    }\n\n                    if (masterConfig.onXhrComplete) {\n                        masterConfig.onXhrComplete(xhr, url);\n                    }\n                }\n            };\n            xhr.send(null);\n        };\n    } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n            typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n        //Why Java, why is this so awkward?\n        text.get = function (url, callback) {\n            var stringBuffer, line,\n                encoding = \"utf-8\",\n                file = new java.io.File(url),\n                lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n                input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n                content = '';\n            try {\n                stringBuffer = new java.lang.StringBuffer();\n                line = input.readLine();\n\n                // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n                // http://www.unicode.org/faq/utf_bom.html\n\n                // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n                if (line && line.length() && line.charAt(0) === 0xfeff) {\n                    // Eat the BOM, since we've already found the encoding on this file,\n                    // and we plan to concatenating this buffer with others; the BOM should\n                    // only appear at the top of a file.\n                    line = line.substring(1);\n                }\n\n                if (line !== null) {\n                    stringBuffer.append(line);\n                }\n\n                while ((line = input.readLine()) !== null) {\n                    stringBuffer.append(lineSeparator);\n                    stringBuffer.append(line);\n                }\n                //Make sure we return a JavaScript string and not a Java string.\n                content = String(stringBuffer.toString()); //String\n            } finally {\n                input.close();\n            }\n            callback(content);\n        };\n    } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n            typeof Components !== 'undefined' && Components.classes &&\n            Components.interfaces)) {\n        //Avert your gaze!\n        Cc = Components.classes;\n        Ci = Components.interfaces;\n        Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n        xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n        text.get = function (url, callback) {\n            var inStream, convertStream, fileObj,\n                readData = {};\n\n            if (xpcIsWindows) {\n                url = url.replace(/\\//g, '\\\\');\n            }\n\n            fileObj = new FileUtils.File(url);\n\n            //XPCOM, you so crazy\n            try {\n                inStream = Cc['@mozilla.org/network/file-input-stream;1']\n                           .createInstance(Ci.nsIFileInputStream);\n                inStream.init(fileObj, 1, 0, false);\n\n                convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n                                .createInstance(Ci.nsIConverterInputStream);\n                convertStream.init(inStream, \"utf-8\", inStream.available(),\n                Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n                convertStream.readString(inStream.available(), readData);\n                convertStream.close();\n                inStream.close();\n                callback(readData.value);\n            } catch (e) {\n                throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n            }\n        };\n    }\n    return text;\n});","requirejs/domReady.js":"/**\n * @license RequireJS domReady 2.0.1 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/domReady for details\n */\n/*jslint */\n/*global require: false, define: false, requirejs: false,\n  window: false, clearInterval: false, document: false,\n  self: false, setInterval: false */\n\n\ndefine(function () {\n    'use strict';\n\n    var isTop, testDiv, scrollIntervalId,\n        isBrowser = typeof window !== \"undefined\" && window.document,\n        isPageLoaded = !isBrowser,\n        doc = isBrowser ? document : null,\n        readyCalls = [];\n\n    function runCallbacks(callbacks) {\n        var i;\n        for (i = 0; i < callbacks.length; i += 1) {\n            callbacks[i](doc);\n        }\n    }\n\n    function callReady() {\n        var callbacks = readyCalls;\n\n        if (isPageLoaded) {\n            //Call the DOM ready callbacks\n            if (callbacks.length) {\n                readyCalls = [];\n                runCallbacks(callbacks);\n            }\n        }\n    }\n\n    /**\n     * Sets the page as loaded.\n     */\n    function pageLoaded() {\n        if (!isPageLoaded) {\n            isPageLoaded = true;\n            if (scrollIntervalId) {\n                clearInterval(scrollIntervalId);\n            }\n\n            callReady();\n        }\n    }\n\n    if (isBrowser) {\n        if (document.addEventListener) {\n            //Standards. Hooray! Assumption here that if standards based,\n            //it knows about DOMContentLoaded.\n            document.addEventListener(\"DOMContentLoaded\", pageLoaded, false);\n            window.addEventListener(\"load\", pageLoaded, false);\n        } else if (window.attachEvent) {\n            window.attachEvent(\"onload\", pageLoaded);\n\n            testDiv = document.createElement('div');\n            try {\n                isTop = window.frameElement === null;\n            } catch (e) {}\n\n            //DOMContentLoaded approximation that uses a doScroll, as found by\n            //Diego Perini: http://javascript.nwbox.com/IEContentLoaded/,\n            //but modified by other contributors, including jdalton\n            if (testDiv.doScroll && isTop && window.external) {\n                scrollIntervalId = setInterval(function () {\n                    try {\n                        testDiv.doScroll();\n                        pageLoaded();\n                    } catch (e) {}\n                }, 30);\n            }\n        }\n\n        //Check if document is no longer loading, and if so, just trigger page load\n        //listeners. Latest webkit browsers also use \"interactive\", and\n        //will fire the onDOMContentLoaded before \"interactive\" but not after\n        //entering \"interactive\" or \"complete\". More details:\n        //http://dev.w3.org/html5/spec/the-end.html#the-end\n        //http://stackoverflow.com/questions/3665561/document-readystate-of-interactive-vs-ondomcontentloaded\n        //Hmm, this is more complicated on further use, see \"firing too early\"\n        //bug: https://github.com/requirejs/domReady/issues/1\n        //so removing the || document.readyState === \"interactive\" test.\n        //There is still a window.onload binding that should get fired if\n        //DOMContentLoaded is missed.\n        if (document.readyState !== \"loading\") {\n            // Handle it asynchronously to allow scripts the opportunity to delay ready\n            setTimeout(pageLoaded);\n        }\n    }\n\n    /** START OF PUBLIC API **/\n\n    /**\n     * Registers a callback for DOM ready. If DOM is already ready, the\n     * callback is called immediately.\n     * @param {Function} callback\n     */\n    function domReady(callback) {\n        if (isPageLoaded) {\n            callback(doc);\n        } else {\n            readyCalls.push(callback);\n        }\n        return domReady;\n    }\n\n    domReady.version = '2.0.1';\n\n    /**\n     * Loader Plugin API method\n     */\n    domReady.load = function (name, req, onLoad, config) {\n        if (config.isBuild) {\n            onLoad(null);\n        } else {\n            domReady(onLoad);\n        }\n    };\n\n    /** END OF PUBLIC API **/\n\n    return domReady;\n});\n","js-cookie/cookie-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'js-cookie/js.cookie'\n], function ($, cookie) {\n    'use strict';\n\n    window.Cookies = window.Cookies || cookie;\n\n    var config = $.cookie = function (key, value, options) {\n        if (value !== undefined) {\n            options = $.extend({}, config.defaults, options);\n\n            return cookie.set(key, value, options);\n        }\n\n        var result = key ? undefined : {},\n            cookies = document.cookie ? document.cookie.split('; ') : [],\n            i;\n\n        for (i = 0; i < cookies.length; i++) {\n            var parts = cookies[i].split('='),\n                name = config.raw ? parts.shift() : decodeURIComponent(parts.shift()),\n                cookieValue = parts.join('=');\n\n            if (key && key === name) {\n                result = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '));\n                break;\n            }\n\n            if (!key && (cookieValue = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '))) !== undefined) {\n                result[name] = cookieValue;\n            }\n        }\n\n        return result;\n    };\n\n    config.defaults = {};\n\n    $.removeCookie = function (key, options) {\n        if ($.cookie(key) === undefined) {\n            return false;\n        }\n\n        $.cookie(key, '', $.extend({}, options, { expires: -1 }));\n        return !$.cookie(key);\n    };\n});\n","js-cookie/js.cookie.js":"/*! js-cookie v3.0.1 | MIT */\n;\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n        typeof define === 'function' && define.amd ? define(factory) :\n            (global = global || self, (function () {\n                var current = global.Cookies;\n                var exports = global.Cookies = factory();\n                exports.noConflict = function () { global.Cookies = current; return exports; };\n            }()));\n}(this, (function () { 'use strict';\n\n    /* eslint-disable no-var */\n    function assign (target) {\n        for (var i = 1; i < arguments.length; i++) {\n            var source = arguments[i];\n            for (var key in source) {\n                target[key] = source[key];\n            }\n        }\n        return target\n    }\n    /* eslint-enable no-var */\n\n    /* eslint-disable no-var */\n    var defaultConverter = {\n        read: function (value) {\n            if (value[0] === '\"') {\n                value = value.slice(1, -1);\n            }\n            return value.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent)\n        },\n        write: function (value) {\n            return encodeURIComponent(value).replace(\n                /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,\n                decodeURIComponent\n            )\n        }\n    };\n    /* eslint-enable no-var */\n\n    /* eslint-disable no-var */\n\n    function init (converter, defaultAttributes) {\n        function set (key, value, attributes) {\n            if (typeof document === 'undefined') {\n                return\n            }\n\n            attributes = assign({}, defaultAttributes, attributes);\n\n            if (typeof attributes.expires === 'number') {\n                attributes.expires = new Date(Date.now() + attributes.expires * 864e5);\n            }\n            if (attributes.expires) {\n                attributes.expires = attributes.expires.toUTCString();\n            }\n\n            key = encodeURIComponent(key)\n                .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n                .replace(/[()]/g, escape);\n\n            var stringifiedAttributes = '';\n            for (var attributeName in attributes) {\n                if (!attributes[attributeName]) {\n                    continue\n                }\n\n                stringifiedAttributes += '; ' + attributeName;\n\n                if (attributes[attributeName] === true) {\n                    continue\n                }\n\n                // Considers RFC 6265 section 5.2:\n                // ...\n                // 3.  If the remaining unparsed-attributes contains a %x3B (\";\")\n                //     character:\n                // Consume the characters of the unparsed-attributes up to,\n                // not including, the first %x3B (\";\") character.\n                // ...\n                stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];\n            }\n\n            return (document.cookie =\n                key + '=' + converter.write(value, key) + stringifiedAttributes)\n        }\n\n        function get (key) {\n            if (typeof document === 'undefined' || (arguments.length && !key)) {\n                return\n            }\n\n            // To prevent the for loop in the first place assign an empty array\n            // in case there are no cookies at all.\n            var cookies = document.cookie ? document.cookie.split('; ') : [];\n            var jar = {};\n            for (var i = 0; i < cookies.length; i++) {\n                var parts = cookies[i].split('=');\n                var value = parts.slice(1).join('=');\n\n                try {\n                    var foundKey = decodeURIComponent(parts[0]);\n                    jar[foundKey] = converter.read(value, foundKey);\n\n                    if (key === foundKey) {\n                        break\n                    }\n                } catch (e) {}\n            }\n\n            return key ? jar[key] : jar\n        }\n\n        return Object.create(\n            {\n                set: set,\n                get: get,\n                remove: function (key, attributes) {\n                    set(\n                        key,\n                        '',\n                        assign({}, attributes, {\n                            expires: -1\n                        })\n                    );\n                },\n                withAttributes: function (attributes) {\n                    return init(this.converter, assign({}, this.attributes, attributes))\n                },\n                withConverter: function (converter) {\n                    return init(assign({}, this.converter, converter), this.attributes)\n                }\n            },\n            {\n                attributes: { value: Object.freeze(defaultAttributes) },\n                converter: { value: Object.freeze(converter) }\n            }\n        )\n    }\n\n    var api = init(defaultConverter, { path: '/' });\n    /* eslint-enable no-var */\n\n    return api;\n\n})));\n","magnifier/magnify.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'magnifier/magnifier'\n], function ($, _) {\n    'use strict';\n\n    return function (config, element) {\n\n        var isTouchEnabled = 'ontouchstart' in document.documentElement,\n            gallerySelector = '[data-gallery-role=\"gallery\"]',\n            magnifierSelector = '[data-gallery-role=\"magnifier\"]',\n            magnifierZoomSelector = '[data-gallery-role=\"magnifier-zoom\"]',\n            zoomInButtonSelector = '[data-gallery-role=\"fotorama__zoom-in\"]',\n            zoomOutButtonSelector = '[data-gallery-role=\"fotorama__zoom-out\"]',\n            fullscreenImageSelector = '[data-gallery-role=\"stage-shaft\"] [data-active=\"true\"] .fotorama__img--full',\n            imageDraggableClass = 'fotorama__img--draggable',\n            imageZoommable = 'fotorama__img--zoommable',\n            zoomInLoaded = 'zoom-in-loaded',\n            zoomOutLoaded = 'zoom-out-loaded',\n            zoomInDisabled = 'fotorama__zoom-in--disabled',\n            zoomOutDisabled = 'fotorama__zoom-out--disabled',\n            keyboardNavigation,\n            videoContainerClass = 'fotorama-video-container',\n            hideMagnifier,\n            dragFlag,\n            endX,\n            transitionEnabled,\n            transitionActive = false,\n            tapFlag = 0,\n            allowZoomOut = false,\n            allowZoomIn = true;\n\n        transitionEnabled = document.documentElement.style.transition !== undefined ||\n            document.documentElement.style.WebkitTransition !== undefined ||\n            document.documentElement.style.MozTransition !== undefined ||\n            document.documentElement.style.MsTransition !== undefined ||\n            document.documentElement.style.OTransition !== undefined;\n\n        /**\n         * Return width and height of original image\n         * @param img original image node\n         * @returns {{rw: number, rh: number}}\n         */\n        function getImageSize(img) {\n            return {\n                rw: img.naturalWidth,\n                rh: img.naturalHeight\n            };\n        }\n\n        /**\n         * Sets min-height and min-width for image to avoid transition bug\n         * @param $image - fullscreen image\n         */\n        function calculateMinSize($image) {\n\n            var minHeight,\n                minWidth,\n                height = $image.height(),\n                width = $image.width(),\n                parentHeight = $image.parent().height(),\n                parentWidth = $image.parent().width();\n\n            if (width > parentWidth || height > parentHeight) {\n\n                if (width / height < parentWidth / parentHeight) {\n                    minHeight = parentHeight;\n                    minWidth = width * (parentHeight / height);\n                } else {\n                    minWidth = parentWidth;\n                    minHeight = height * parentWidth / width;\n                }\n                $image.css({\n                    'min-width': minWidth,\n                    'min-height': minHeight\n                });\n            }\n        }\n\n        function toggleZoomable($image, flag) {\n            if (flag) {\n                $image.css({\n                    'min-width': $image.width(),\n                    'min-height': $image.height(),\n                    'width': $image.width(),\n                    'height': $image.height()\n                }).addClass(imageZoommable);\n            } else {\n                $image.css({\n                    width: '',\n                    height: '',\n                    top: '',\n                    left: '',\n                    right: '',\n                    bottom: ''\n                }).removeClass(imageZoommable);\n                calculateMinSize($image);\n            }\n        }\n\n        function resetVars($image) {\n            allowZoomIn = true;\n            allowZoomOut = dragFlag = transitionActive = false;\n            $image.hasClass(imageDraggableClass) && $image.removeClass(imageDraggableClass);\n            toggleZoomable($image, false);\n        }\n\n        /**\n         * Set state for zoom controls.\n         * If state is true, zoom controls will be visible.\n         * IF state is false, zoom controls will be hidden.\n         * @param isHide\n         */\n        function hideZoomControls(isHide) {\n            if (isHide) {\n                $(zoomInButtonSelector).addClass(zoomInDisabled);\n                $(zoomOutButtonSelector).addClass(zoomOutDisabled);\n            } else {\n                $(zoomInButtonSelector).removeClass(zoomInDisabled);\n                $(zoomOutButtonSelector).removeClass(zoomOutDisabled);\n            }\n        }\n\n        /**\n         * Asynchronus control visibility of zoom buttons.\n         * If image bigger than her wrapper. Zoom controls must visible.\n         * @param path - image source path\n         * @param $image\n         */\n        function asyncToggleZoomButtons(path, $image) {\n            var img = new Image();\n\n            img.onload = function () {\n                this.height > $image.parent().height() || this.width > $image.parent().width() ?\n                    hideZoomControls(false) : hideZoomControls(true);\n            };\n            img.src = path;\n        }\n\n        /**\n         * Control visibility of zoom buttons.\n         * Zoom controls must be invisible for video content and touch devices.\n         * On touch devices active pinchIn/pinchOut.\n         * @param $image\n         * @param isTouchScreen - true for touch devices\n         * @param isVideoActiveFrame - true for active video frame\n         */\n        function toggleZoomButtons($image, isTouchScreen, isVideoActiveFrame) {\n            var path = $image.attr('src');\n\n            if (path && !isTouchScreen && !isVideoActiveFrame) {\n                asyncToggleZoomButtons(path, $image);\n            } else {\n                hideZoomControls(true);\n            }\n        }\n\n        /**\n         * Handle resize event in fullscreen.\n         * @param $image - Fullscreen image.\n         * @param e - Event.\n         */\n        function resizeHandler(e, $image) {\n            var imageSize,\n                parentWidth,\n                parentHeight,\n                isImageSmall,\n                isImageFit;\n\n            if (!e.data.$image || !e.data.$image.length)\n                return;\n\n            imageSize = getImageSize($(fullscreenImageSelector)[0]);\n            parentWidth = e.data.$image.parent().width();\n            parentHeight = e.data.$image.parent().height();\n            isImageSmall = parentWidth >= imageSize.rw && parentHeight >= imageSize.rh;\n            isImageFit = parentWidth > e.data.$image.width() && parentHeight > e.data.$image.height();\n\n            toggleZoomButtons(e.data.$image, isTouchEnabled, checkForVideo(e.data.fotorama.activeFrame.$stageFrame));\n            calculateMinSize(e.data.$image);\n\n            if (e.data.$image.hasClass(imageZoommable) && !allowZoomOut || isImageSmall || isImageFit) {\n                resetVars(e.data.$image);\n            }\n\n            if (!isImageSmall) {\n                toggleStandartNavigation();\n            }\n        }\n\n        function getTopValue($image, topProp, step, height, containerHeight) {\n            var top;\n\n            if (parseInt($image.css('marginTop')) || parseInt($image.css('marginLeft'))) {\n                top = dragFlag ? topProp - step / 4 : 0;\n                top = top < containerHeight - height ? containerHeight - height : top;\n                top = top > height - containerHeight ? height - containerHeight : top;\n            } else {\n                top = topProp + step / 2;\n                top = top < containerHeight - height ? containerHeight - height : top;\n                top = top > 0 ? 0 : top;\n\n                if (!dragFlag && step < 0) {\n                    top = top < (containerHeight - height) / 2 ? (containerHeight - height) / 2 : top;\n                }\n            }\n\n            return top;\n        }\n\n        function getLeftValue(leftProp, step, width, containerWidth) {\n            var left;\n\n            left = leftProp + step / 2;\n            left = left < containerWidth - width ? containerWidth - width : left;\n            left = left > 0 ? 0 : left;\n\n            if (!dragFlag && step < 0) {\n                left = left < (containerWidth - width) / 2 ? (containerWidth - width) / 2 : left;\n            }\n\n            return left;\n        }\n\n        function checkFullscreenImagePosition($image, dimentions, widthStep, heightStep) {\n            var $imageContainer,\n                containerWidth,\n                containerHeight,\n                settings,\n                top,\n                left,\n                right,\n                bottom,\n                ratio;\n\n            if ($(gallerySelector).data('fotorama').fullScreen) {\n                transitionActive = true;\n                $imageContainer = $image.parent();\n                containerWidth = $imageContainer.width();\n                containerHeight = $imageContainer.height();\n                top = $image.position().top;\n                left = $image.position().left;\n                ratio = $image.width() / $image.height();\n                dimentions.height = isNaN(dimentions.height) ? dimentions.width / ratio : dimentions.height;\n                dimentions.width = isNaN(dimentions.width) ? dimentions.height * ratio : dimentions.width;\n\n                top = dimentions.height >= containerHeight ?\n                    getTopValue($image, top, heightStep, dimentions.height, containerHeight) : 0;\n\n                left = dimentions.width >= containerWidth ?\n                    getLeftValue(left, widthStep, dimentions.width, containerWidth) : 0;\n\n                right = dragFlag && left < (containerWidth - dimentions.width) / 2 ? 0 : left;\n                bottom = dragFlag ? 0 : top;\n\n                settings = $.extend(dimentions, {\n                    top: top,\n                    left: left,\n                    right: right\n                });\n\n                $image.css(settings);\n            }\n        }\n\n        /**\n         * Toggles fotorama's keyboard and mouse/touch navigation.\n         */\n        function toggleStandartNavigation() {\n            var $selectable =\n                    $('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')\n                    .not('[tabindex=-1], [disabled], :hidden'),\n                fotorama = $(gallerySelector).data('fotorama'),\n                $focus = $(':focus'),\n                index;\n\n            if (fotorama.fullScreen) {\n\n                $selectable.each(function (number) {\n\n                    if ($(this).is($focus)) {\n                        index = number;\n                    }\n                });\n\n                fotorama.setOptions({\n                    swipe: !allowZoomOut,\n                    keyboard: !allowZoomOut\n                });\n\n                if (_.isNumber(index)) {\n                    $selectable.eq(index).trigger('focus');\n                }\n            }\n        }\n\n        function zoomIn(e, xStep, yStep) {\n            var $image,\n                imgOriginalSize,\n                imageWidth,\n                imageHeight,\n                zoomWidthStep,\n                zoomHeightStep,\n                widthResult,\n                heightResult,\n                ratio,\n                dimentions = {};\n\n            if (allowZoomIn && (!transitionEnabled || !transitionActive) && (isTouchEnabled ||\n                !$(zoomInButtonSelector).hasClass(zoomInDisabled))) {\n                $image = $(fullscreenImageSelector);\n                imgOriginalSize = getImageSize($image[0]);\n                imageWidth = $image.width();\n                imageHeight = $image.height();\n                ratio = imageWidth / imageHeight;\n                allowZoomOut = true;\n                toggleStandartNavigation();\n\n                if (!$image.hasClass(imageZoommable)) {\n                    toggleZoomable($image, true);\n                }\n\n                e.preventDefault();\n\n                if (imageWidth >= imageHeight) {\n                    zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);\n                    widthResult = imageWidth + zoomWidthStep;\n\n                    if (widthResult >= imgOriginalSize.rw) {\n                        widthResult = imgOriginalSize.rw;\n                        zoomWidthStep = xStep || widthResult - imageWidth;\n                        allowZoomIn = false;\n                    }\n                    heightResult = widthResult / ratio;\n                    zoomHeightStep = yStep || heightResult - imageHeight;\n                } else {\n                    zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);\n                    heightResult = imageHeight + zoomHeightStep;\n\n                    if (heightResult >= imgOriginalSize.rh) {\n                        heightResult = imgOriginalSize.rh;\n                        zoomHeightStep = yStep || heightResult - imageHeight;\n                        allowZoomIn = false;\n                    }\n                    widthResult = heightResult * ratio;\n                    zoomWidthStep = xStep || widthResult - imageWidth;\n                }\n\n                if (imageWidth >= imageHeight && imageWidth !== imgOriginalSize.rw) {\n                    dimentions = $.extend(dimentions, {\n                        width: widthResult,\n                        height: 'auto'\n                    });\n                    checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep);\n\n                } else if (imageWidth < imageHeight && imageHeight !== imgOriginalSize.rh) {\n                    dimentions = $.extend(dimentions, {\n                        width: 'auto',\n                        height: heightResult\n                    });\n                    checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep);\n                }\n            }\n\n            return false;\n        }\n\n        function zoomOut(e, xStep, yStep) {\n            var $image,\n                widthResult,\n                heightResult,\n                dimentions,\n                parentWidth,\n                parentHeight,\n                imageWidth,\n                imageHeight,\n                zoomWidthStep,\n                zoomHeightStep,\n                ratio,\n                fitIntoParent;\n\n            if (allowZoomOut && (!transitionEnabled || !transitionActive) && (isTouchEnabled ||\n                !$(zoomOutButtonSelector).hasClass(zoomOutDisabled))) {\n                allowZoomIn = true;\n                $image = $(fullscreenImageSelector);\n                parentWidth = $image.parent().width();\n                parentHeight = $image.parent().height();\n                imageWidth = $image.width();\n                imageHeight = $image.height();\n                ratio = imageWidth / imageHeight;\n\n                e.preventDefault();\n\n                if (imageWidth >= imageHeight) {\n                    zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);\n                    widthResult = imageWidth - zoomWidthStep;\n                    heightResult = widthResult / ratio;\n                    zoomHeightStep = yStep || imageHeight - heightResult;\n                } else {\n                    zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);\n                    heightResult = imageHeight - zoomHeightStep;\n                    widthResult = heightResult * ratio;\n                    zoomWidthStep = xStep || imageWidth - widthResult;\n                }\n\n                fitIntoParent = function () {\n                    if (ratio > parentWidth / parentHeight) {\n                        widthResult = parentWidth;\n                        zoomWidthStep = imageWidth - widthResult;\n                        heightResult = widthResult / ratio;\n                        zoomHeightStep = imageHeight - heightResult;\n                        dimentions = {\n                            width: widthResult,\n                            height: 'auto'\n                        };\n                    } else {\n                        heightResult = parentHeight;\n                        zoomHeightStep = imageHeight - heightResult;\n                        widthResult = heightResult * ratio;\n                        zoomWidthStep = imageWidth - widthResult;\n                        dimentions = {\n                            width: 'auto',\n                            height: heightResult\n                        };\n                    }\n                    checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);\n                };\n\n                if (imageWidth >= imageHeight) {\n                    if (widthResult > parentWidth) {\n                        dimentions = {\n                            width: widthResult,\n                            height: 'auto'\n                        };\n                        checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);\n                    } else if (heightResult > parentHeight) {\n                        dimentions = {\n                            width: widthResult,\n                            height: 'auto'\n                        };\n                        checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);\n                    } else {\n                        allowZoomOut = dragFlag = false;\n                        toggleStandartNavigation();\n                        fitIntoParent();\n                    }\n                } else if (heightResult > parentHeight) {\n                    dimentions = {\n                        width: 'auto',\n                        height: heightResult\n                    };\n                    checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);\n                } else if (widthResult > parentWidth) {\n                    dimentions = {\n                        width: 'auto',\n                        height: heightResult\n                    };\n                    checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);\n                } else {\n                    allowZoomOut = dragFlag = false;\n                    toggleStandartNavigation();\n                    fitIntoParent();\n                }\n            }\n\n            return false;\n        }\n\n        /**\n         * Bind event on scroll on active item in fotorama\n         * @param e\n         * @param fotorama - object of fotorama\n         */\n        function mousewheel(e, fotorama, element) {\n            var $fotoramaStage = fotorama.activeFrame.$stageFrame,\n                fotoramaStage = $fotoramaStage.get(0);\n\n            function onWheel(e) {\n                var delta = e.deltaY || e.wheelDelta,\n                    ev = e || window.event;\n\n                if ($(gallerySelector).data('fotorama').fullScreen) {\n\n                    if (e.deltaY) {\n                        if (delta > 0) {\n                            zoomOut(ev);\n                        } else {\n                            zoomIn(ev);\n                        }\n                    } else if (delta > 0) {\n                        zoomIn(ev);\n                    } else {\n                        zoomOut(ev);\n                    }\n\n                    e.preventDefault ? e.preventDefault() : e.returnValue = false;\n                }\n            }\n\n            if (!$fotoramaStage.hasClass('magnify-wheel-loaded')) {\n                if (fotoramaStage && fotoramaStage.addEventListener) {\n                    if ('onwheel' in document) {\n                        fotoramaStage.addEventListener('wheel', onWheel, { passive: true });\n                    } else if ('onmousewheel' in document) {\n                        fotoramaStage.addEventListener('mousewheel', onWheel);\n                    } else {\n                        fotoramaStage.addEventListener('MozMousePixelScroll', onWheel);\n                    }\n                    $fotoramaStage.addClass('magnify-wheel-loaded');\n                }\n            }\n        }\n\n        /**\n         * Method which makes draggable picture. Also work on touch devices.\n         */\n        function magnifierFullscreen(fotorama) {\n            var isDragActive = false,\n                startX,\n                startY,\n                imagePosX,\n                imagePosY,\n                touch,\n                swipeSlide,\n                $gallery = $(gallerySelector),\n                $image = $(fullscreenImageSelector, $gallery),\n                $imageContainer = $('[data-gallery-role=\"stage-shaft\"] [data-active=\"true\"]'),\n                gallery = $gallery.data('fotorama'),\n                pinchDimention;\n\n            swipeSlide = _.throttle(function (direction) {\n                $(gallerySelector).data('fotorama').show(direction);\n            }, 500, {\n                trailing: false\n            });\n\n            /**\n             * Returns top position value for passed jQuery object.\n             *\n             * @param $el\n             * @return {number}\n             */\n            function getTop($el) {\n                return parseInt($el.get(0).style.top);\n            }\n\n            function shiftImage(dx, dy, e) {\n                var top = +imagePosY + dy,\n                    left = +imagePosX + dx,\n                    swipeCondition = $image.width() / 10 + 20;\n\n                dragFlag = true;\n\n                if ($image.offset().left === $imageContainer.offset().left + $imageContainer.width() - $image.width() && e.keyCode === 39 ||\n                    endX - 1 < $imageContainer.offset().left + $imageContainer.width() - $image.width() && dx < 0 &&\n                    _.isNumber(endX) &&\n                    (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {\n                    endX = null;\n                    swipeSlide('>');\n\n                    return;\n                }\n\n                if ($image.offset().left === $imageContainer.offset().left && dx !== 0 && e.keyCode === 37 ||\n                    endX === $imageContainer.offset().left && dx > 0 &&\n                    (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {\n                    endX = null;\n                    swipeSlide('<');\n\n                    return;\n                }\n\n                if ($image.height() > $imageContainer.height()) {\n                    if ($imageContainer.height() > $image.height() + top) {\n                        $image.css('top', $imageContainer.height() - $image.height());\n                    } else {\n                        top = $image.height() - getTop($image) - $imageContainer.height();\n                        dy = dy < top ? dy : top;\n                        $image.css('top', getTop($image) + dy);\n                    }\n                }\n\n                if ($image.width() > $imageContainer.width()) {\n\n                    if ($imageContainer.offset().left + $imageContainer.width() > left + $image.width()) {\n                        left = $imageContainer.offset().left + $imageContainer.width() - $image.width();\n                    } else {\n                        left = $imageContainer.offset().left < left ? $imageContainer.offset().left : left;\n                    }\n                    $image.offset({\n                        'left': left\n                    });\n                    $image.css('right', '');\n                } else if (Math.abs(dy) < 1 && allowZoomOut &&\n                    !(e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {\n                    dx < 0 ? $(gallerySelector).data('fotorama').show('>') : $(gallerySelector).data('fotorama').show('<');\n                }\n\n                if ($image.width() <= $imageContainer.width() && allowZoomOut &&\n                    (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove') &&\n                    Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > swipeCondition) {\n                    dx < 0 ? swipeSlide('>') : swipeSlide('<');\n                }\n            }\n\n            /**\n             * Sets image size to original or fit in parent block\n             * @param e - event object\n             */\n            function dblClickHandler(e) {\n                var imgOriginalSize = getImageSize($image[0]),\n                    proportions;\n\n                if (imgOriginalSize.rh < $image.parent().height() && imgOriginalSize.rw < $image.parent().width()) {\n                    return;\n                }\n\n                proportions = imgOriginalSize.rw / imgOriginalSize.rh;\n\n                if (allowZoomIn) {\n                    zoomIn(e, imgOriginalSize.rw - $image.width(), imgOriginalSize.rh - $image.height());\n                } else if (proportions > $imageContainer.width() / $imageContainer.height()) {\n                    zoomOut(e, imgOriginalSize.rw - $imageContainer.width(), imgOriginalSize.rw / proportions);\n                } else {\n                    zoomOut(e, imgOriginalSize.rw * proportions, imgOriginalSize.rh - $imageContainer.height());\n                }\n            }\n\n            function detectDoubleTap(e) {\n                var now = new Date().getTime(),\n                    timesince = now - tapFlag;\n\n                if (timesince < 400 && timesince > 0) {\n                    transitionActive = false;\n                    tapFlag = 0;\n                    dblClickHandler(e);\n                } else {\n                    tapFlag = new Date().getTime();\n                }\n            }\n\n            if (isTouchEnabled) {\n                $image.off('tap');\n                $image.on('tap', function (e) {\n                    if (e.originalEvent.originalEvent.touches.length === 0) {\n                        detectDoubleTap(e);\n                    }\n                });\n            } else {\n                $image.off('dblclick');\n                $image.on('dblclick', dblClickHandler);\n            }\n\n            if (gallery.fullScreen) {\n                toggleZoomButtons($image, isTouchEnabled, checkForVideo(fotorama.activeFrame.$stageFrame));\n            }\n\n            function getDimention(event) {\n                return Math.sqrt(\n                    (event.touches[0].clientX - event.touches[1].clientX) * (event.touches[0].clientX - event.touches[1].clientX) +\n                    (event.touches[0].clientY - event.touches[1].clientY) * (event.touches[0].clientY - event.touches[1].clientY));\n            }\n\n            $image.off(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown');\n            $image.on(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown', function (e) {\n                if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) {\n                    e.preventDefault();\n                    pinchDimention = getDimention(e.originalEvent);\n                    isDragActive = false;\n\n                    if ($image.hasClass(imageDraggableClass)) {\n                        $image.removeClass(imageDraggableClass);\n                    }\n                } else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) {\n                    imagePosY = getTop($image);\n                    imagePosX = $image.offset().left;\n\n                    if (isTouchEnabled) {\n                        touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];\n                        e.clientX = touch.pageX;\n                        e.clientY = touch.pageY;\n                    }\n                    startX = e.clientX || e.originalEvent.clientX;\n                    startY = e.clientY || e.originalEvent.clientY;\n                    isDragActive = true;\n                }\n\n                if ($image.offset() && $image.width() > $imageContainer.width()) {\n                    endX = $image.offset().left;\n                }\n            });\n\n            $image.off(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove');\n            $image.on(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove', function (e) {\n                if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) {\n                    e.preventDefault();\n                    var currentDimention = getDimention(e.originalEvent);\n\n                    if ($image.hasClass(imageDraggableClass)) {\n                        $image.removeClass(imageDraggableClass);\n                    }\n\n                    if (currentDimention < pinchDimention) {\n                        zoomOut(e);\n                        pinchDimention = currentDimention;\n                    } else if (currentDimention > pinchDimention) {\n                        zoomIn(e);\n                        pinchDimention = currentDimention;\n                    }\n                } else {\n                    var clientX,\n                        clientY;\n\n                    if (gallery.fullScreen && isDragActive && (!transitionEnabled || !transitionActive)) {\n\n                        if (allowZoomOut && !$image.hasClass(imageDraggableClass)) {\n                            $image.addClass(imageDraggableClass);\n                        }\n                        clientX = e.clientX || e.originalEvent.clientX;\n                        clientY = e.clientY || e.originalEvent.clientY;\n\n                        e.preventDefault();\n\n                        if (isTouchEnabled) {\n                            touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];\n                            clientX = touch.pageX;\n                            clientY = touch.pageY;\n                        }\n\n                        if (allowZoomOut) {\n                            imagePosY = getTop($(fullscreenImageSelector, $gallery));\n                            shiftImage(clientX - startX, clientY - startY, e);\n                        }\n                    }\n                }\n            });\n\n            $image.off('transitionend webkitTransitionEnd mozTransitionEnd msTransitionEnd ');\n            $image.on('transitionend webkitTransitionEnd mozTransitionEnd msTransitionEnd', function () {\n                transitionActive = false;\n            });\n\n            if (keyboardNavigation) {\n                $(document).off('keydown', keyboardNavigation);\n            }\n\n            /**\n             * Replaces original navigations with better one\n             * @param e - event object\n             */\n            keyboardNavigation = function (e) {\n                var step = 40,\n                    $focus = $(':focus'),\n                    isFullScreen = $(gallerySelector).data('fotorama').fullScreen,\n                    initVars = function () {\n                        imagePosX = $(fullscreenImageSelector, $gallery).offset().left;\n                        imagePosY = getTop($(fullscreenImageSelector, $gallery));\n                    };\n\n                if (($focus.attr('data-gallery-role') || !$focus.length) && allowZoomOut) {\n                    if (isFullScreen) {\n                        imagePosX = $(fullscreenImageSelector, $(gallerySelector)).offset().left;\n                        imagePosY = getTop($(fullscreenImageSelector, $(gallerySelector)));\n                    }\n\n                    if (e.keyCode === 39) {\n\n                        if (isFullScreen) {\n                            initVars();\n                            shiftImage(-step, 0, e);\n                        }\n                    }\n\n                    if (e.keyCode === 38) {\n\n                        if (isFullScreen) {\n                            initVars();\n                            shiftImage(0, step, e);\n                        }\n                    }\n\n                    if (e.keyCode === 37) {\n\n                        if (isFullScreen) {\n                            initVars();\n                            shiftImage(step, 0, e);\n                        }\n                    }\n\n                    if (e.keyCode === 40) {\n\n                        if (isFullScreen) {\n                            e.preventDefault();\n                            initVars();\n                            shiftImage(0, -step, e);\n                        }\n                    }\n                }\n\n                if (e.keyCode === 27 && isFullScreen && allowZoomOut) {\n                    $(gallerySelector).data('fotorama').cancelFullScreen();\n                }\n            };\n\n            /**\n             * @todo keyboard navigation through Fotorama Api.\n             */\n            $(document).on('keydown', keyboardNavigation);\n\n            $(document).on(isTouchEnabled ? 'touchend' : 'mouseup pointerup MSPointerUp', function (e) {\n                if (gallery.fullScreen) {\n\n                    if ($image.offset() && $image.width() > $imageContainer.width()) {\n                        endX = $image.offset().left;\n                    }\n\n                    isDragActive = false;\n                    $image.removeClass(imageDraggableClass);\n                }\n            });\n\n            $(window).off('resize', resizeHandler);\n            $(window).on('resize', {\n                $image: $image,\n                fotorama: fotorama\n            }, resizeHandler);\n        }\n\n        /**\n         * Hides magnifier preview and zoom blocks.\n         */\n        hideMagnifier = function () {\n            $(magnifierSelector).empty().hide();\n            $(magnifierZoomSelector).remove();\n        };\n\n        /**\n         * Check is active frame in gallery include video content.\n         * If true activeFrame contain video.\n         * @param $stageFrame - active frame in gallery\n         * @returns {*|Boolean}\n         */\n        function checkForVideo($stageFrame) {\n            return $stageFrame.hasClass(videoContainerClass);\n        }\n\n        /**\n         * Hides magnifier on drag and while arrow click.\n         */\n        function behaveOnDrag(e, initPos) {\n            var pos = [e.pageX, e.pageY],\n                isArrow = $(e.target).data('gallery-role') === 'arrow',\n                isClick = initPos[0] === pos[0] && initPos[1] === pos[1],\n                isImg = $(e.target).parent().data('active');\n\n            if (isArrow || isImg && !isClick) {\n                hideMagnifier();\n            }\n        }\n\n        if (config.magnifierOpts.enabled) {\n            $(element).on('pointerdown mousedown MSPointerDown', function (e) {\n                var pos = [e.pageX, e.pageY];\n\n                $(element).on('mousemove pointermove MSPointerMove', function (ev) {\n                    navigator.msPointerEnabled ? hideMagnifier() : behaveOnDrag(ev, pos);\n                });\n                $(document).on('mouseup pointerup MSPointerUp', function () {\n                    $(element).off('mousemove pointermove MSPointerMove');\n                });\n            });\n        }\n\n        $.extend(config.magnifierOpts, {\n            zoomable: false,\n            thumb: '.fotorama__img',\n            largeWrapper: '[data-gallery-role=\"magnifier\"]',\n            height: config.magnifierOpts.height || function () {\n                return $('[data-active=\"true\"]').height();\n            },\n            width: config.magnifierOpts.width || function () {\n                var productMedia = $(gallerySelector).parent().parent();\n\n                return productMedia.parent().width() - productMedia.width() - 20;\n            },\n            left: config.magnifierOpts.left || function () {\n                return $(gallerySelector).offset().left + $(gallerySelector).width() + 20;\n            },\n            top: config.magnifierOpts.top || function () {\n                return $(gallerySelector).offset().top;\n            }\n        });\n\n        $(element).on('fotorama:load fotorama:showend fotorama:fullscreenexit fotorama:ready', function (e, fotorama) {\n            var $activeStageFrame = $(gallerySelector).data('fotorama').activeFrame.$stageFrame;\n\n            if (!$activeStageFrame.find(magnifierZoomSelector).length) {\n                hideMagnifier();\n\n                if (config.magnifierOpts) {\n                    config.magnifierOpts.large = $(gallerySelector).data('fotorama').activeFrame.img;\n                    config.magnifierOpts.full = fotorama.data[fotorama.activeIndex].original;\n                    !checkForVideo($activeStageFrame) && $($activeStageFrame).magnify(config.magnifierOpts);\n                }\n            }\n        });\n\n        $(element).on('gallery:loaded', function (e) {\n            var $prevImage;\n\n            $(element).find(gallerySelector)\n                .on('fotorama:ready', function (e, fotorama) {\n                    var $zoomIn = $(zoomInButtonSelector),\n                        $zoomOut = $(zoomOutButtonSelector);\n\n                    if (!$zoomIn.hasClass(zoomInLoaded)) {\n                        $zoomIn.on('click touchstart', zoomIn);\n                        $zoomIn.on('mousedown', function (e) {\n                            e.stopPropagation();\n                        });\n\n                        $zoomIn.on('keyup', function (e) {\n\n                            if (e.keyCode === 13) {\n                                zoomIn(e);\n                            }\n                        });\n\n                        $(window).on('keyup', function (e) {\n\n                            if (e.keyCode === 107 || fotorama.fullscreen) {\n                                zoomIn(e);\n                            }\n                        });\n\n                        $zoomIn.addClass(zoomInLoaded);\n                    }\n\n                    if (!$zoomOut.hasClass(zoomOutLoaded)) {\n                        $zoomOut.on('click touchstart', zoomOut);\n                        $zoomOut.on('mousedown', function (e) {\n                            e.stopPropagation();\n                        });\n\n                        $zoomOut.on('keyup', function (e) {\n\n                            if (e.keyCode === 13) {\n                                zoomOut(e);\n                            }\n                        });\n\n                        $(window).on('keyup', function (e) {\n\n                            if (e.keyCode === 109 || fotorama.fullscreen) {\n                                zoomOut(e);\n                            }\n                        });\n\n                        $zoomOut.addClass(zoomOutLoaded);\n                    }\n                })\n                .on('fotorama:fullscreenenter fotorama:showend', function (e, fotorama) {\n                    hideMagnifier();\n\n                    if (!$(fullscreenImageSelector).is($prevImage)) {\n                        resetVars($(fullscreenImageSelector));\n                    }\n                    magnifierFullscreen(fotorama);\n                    mousewheel(e, fotorama, element);\n\n                    if ($prevImage) {\n                        calculateMinSize($prevImage);\n\n                        if (!$(fullscreenImageSelector).is($prevImage)) {\n                            resetVars($prevImage);\n                        }\n                    }\n\n                    toggleStandartNavigation();\n                })\n                .on('fotorama:load', function (e, fotorama) {\n                    if ($(gallerySelector).data('fotorama').fullScreen) {\n                        toggleZoomButtons($(fullscreenImageSelector), isTouchEnabled,\n                            checkForVideo(fotorama.activeFrame.$stageFrame));\n                    }\n                    magnifierFullscreen(fotorama);\n                })\n                .on('fotorama:show', function (e, fotorama) {\n                    $prevImage = _.clone($(fullscreenImageSelector));\n                    hideMagnifier();\n                })\n                .on('fotorama:fullscreenexit', function (e, fotorama) {\n                    resetVars($(fullscreenImageSelector));\n                    hideMagnifier();\n                    hideZoomControls(true);\n                });\n        });\n\n        return config;\n    };\n});\n","magnifier/magnifier.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function ($) {\n    $.fn.magnify = function (options) {\n        'use strict';\n\n        var magnify = new Magnify($(this), options);\n\n        /* events must be tracked here */\n\n        /**\n         * Return that from _init function\n         *\n         */\n        return magnify;\n    };\n\n    function Magnify(element, options) {\n        var customUserOptions = options || {},\n            $box = $(element),\n            $thumb,\n            that = this,\n            largeWrapper = options.largeWrapper || '.magnifier-preview',\n            $magnifierPreview = $(largeWrapper);\n\n        curThumb = null,\n        magnifierOptions = {\n            x: 0,\n            y: 0,\n            w: 0,\n            h: 0,\n            lensW: 0,\n            lensH: 0,\n            lensBgX: 0,\n            lensBgY: 0,\n            largeW: 0,\n            largeH: 0,\n            largeL: 0,\n            largeT: 0,\n            zoom: 2,\n            zoomMin: 1.1,\n            zoomMax: 5,\n            mode: 'outside',\n            eventType: 'click',\n            status: 0,\n            zoomAttached: false,\n            zoomable: customUserOptions.zoomable !== undefined ?\n                customUserOptions.zoomable\n                : false,\n            onthumbenter: customUserOptions.onthumbenter !== undefined ?\n                customUserOptions.onthumbenter\n                : null,\n            onthumbmove: customUserOptions.onthumbmove !== undefined ?\n                customUserOptions.onthumbmove\n                : null,\n            onthumbleave: customUserOptions.onthumbleave !== undefined ?\n                customUserOptions.onthumbleave\n                : null,\n            onzoom: customUserOptions.onzoom !== undefined ?\n                customUserOptions.onzoom\n                : null\n        },\n        pos = {\n            t: 0,\n            l: 0,\n            x: 0,\n            y: 0\n        },\n        gId = 0,\n        status = 0,\n        curIdx = '',\n        curLens = null,\n        curLarge = null,\n        lensbg = customUserOptions.bg !== undefined ?\n            customUserOptions.lensbg\n            : true,\n        gZoom = customUserOptions.zoom !== undefined ?\n            customUserOptions.zoom\n            : magnifierOptions.zoom,\n        gZoomMin = customUserOptions.zoomMin !== undefined ?\n            customUserOptions.zoomMin\n            : magnifierOptions.zoomMin,\n        gZoomMax = customUserOptions.zoomMax !== undefined ?\n            customUserOptions.zoomMax\n            : magnifierOptions.zoomMax,\n        gMode = customUserOptions.mode || magnifierOptions.mode,\n        gEventType = customUserOptions.eventType || magnifierOptions.eventType,\n        data = {},\n        inBounds = false,\n        isOverThumb = false,\n        rate = 1,\n        paddingX = 0,\n        paddingY = 0,\n        enabled = true,\n        showWrapper = true;\n\n        var MagnifyCls = {\n            magnifyHidden: 'magnify-hidden',\n            magnifyOpaque: 'magnify-opaque',\n            magnifyFull: 'magnify-fullimage'\n        };\n\n        /**\n         * Update Lens positon on.\n         *\n         */\n        that.update = function () {\n            updateLensOnLoad();\n        };\n\n        /**\n         * Init new Magnifier\n         *\n         */\n        that.init = function () {\n            _init($box, options);\n        };\n\n        function _toBoolean(str) {\n            if (typeof str === 'string') {\n                if (str === 'true') {\n                    return true;\n                } else if (str === 'false' || '') {\n                    return false;\n                }\n                console.warn('Wrong type: can\\'t be transformed to Boolean');\n\n            } else if (typeof str === 'boolean') {\n                return str;\n            }\n        }\n\n        function createLens(thumb) {\n            if ($(thumb).siblings('.magnify-lens').length) {\n                return false;\n            }\n            var lens = $('<div class=\"magnify-lens magnify-hidden\" data-gallery-role=\"magnifier-zoom\"></div>');\n\n            $(thumb).parent().append(lens);\n        }\n\n        function updateLensOnLoad(idSelectorMainImg, thumb, largeImgInMagnifyLens, largeWrapper) {\n            var magnifyLensElement= $box.find('.magnify-lens'),\n                textWrapper;\n\n            if (data[idSelectorMainImg].status === 1) {\n                textWrapper = $('<div class=\"magnifier-loader-text\"></div>');\n                magnifyLensElement.className = 'magnifier-loader magnify-hidden';\n                textWrapper.html('Loading...');\n                magnifyLensElement.html('').append(textWrapper);\n            } else if (data[idSelectorMainImg].status === 2) {\n                magnifyLensElement.addClass(MagnifyCls.magnifyHidden);\n                magnifyLensElement.html('');\n\n                largeImgInMagnifyLens.id = idSelectorMainImg + '-large';\n                largeImgInMagnifyLens.style.width = data[idSelectorMainImg].largeImgInMagnifyLensWidth + 'px';\n                largeImgInMagnifyLens.style.height = data[idSelectorMainImg].largeImgInMagnifyLensHeight + 'px';\n                largeImgInMagnifyLens.className = 'magnifier-large magnify-hidden';\n\n                if (data[idSelectorMainImg].mode === 'inside') {\n                    magnifyLensElement.append(largeImgInMagnifyLens);\n                } else {\n                    largeWrapper.html('').append(largeImgInMagnifyLens);\n                }\n            }\n\n            data[idSelectorMainImg].lensH = data[idSelectorMainImg].lensH > $thumb.height() ? $thumb.height() : data[idSelectorMainImg].lensH;\n\n            if (Math.round(data[idSelectorMainImg].lensW) === 0) {\n                magnifyLensElement.css('display', 'none');\n            } else {\n                magnifyLensElement.css({\n                    width: Math.round(data[idSelectorMainImg].lensW) + 'px',\n                    height: Math.round(data[idSelectorMainImg].lensH) + 'px',\n                    display: ''\n                });\n            }\n        }\n\n        function getMousePos() {\n            var xPos = pos.x - magnifierOptions.x,\n                yPos = pos.y - magnifierOptions.y,\n                t,\n                l;\n\n            inBounds =  xPos < 0 || yPos < 0 || xPos > magnifierOptions.w || yPos > magnifierOptions.h  ? false : true;\n\n            l = xPos - magnifierOptions.lensW / 2;\n            t = yPos - magnifierOptions.lensH / 2;\n\n            if (xPos < magnifierOptions.lensW / 2) {\n                l = 0;\n            }\n\n            if (yPos < magnifierOptions.lensH / 2) {\n                t = 0;\n            }\n\n            if (xPos - magnifierOptions.w + Math.ceil(magnifierOptions.lensW / 2) > 0) {\n                l = magnifierOptions.w - Math.ceil(magnifierOptions.lensW + 2);\n            }\n\n            if (yPos - magnifierOptions.h + Math.ceil(magnifierOptions.lensH / 2) > 0) {\n                t = magnifierOptions.h - Math.ceil(magnifierOptions.lensH);\n            }\n\n            pos.l = l;\n            pos.t = t;\n\n            magnifierOptions.lensBgX = pos.l;\n            magnifierOptions.lensBgY = pos.t;\n\n            if (magnifierOptions.mode === 'inside') {\n                magnifierOptions.largeL = Math.round(xPos * (magnifierOptions.zoom - magnifierOptions.lensW / magnifierOptions.w));\n                magnifierOptions.largeT = Math.round(yPos * (magnifierOptions.zoom - magnifierOptions.lensH / magnifierOptions.h));\n            } else {\n                magnifierOptions.largeL = Math.round(magnifierOptions.lensBgX * magnifierOptions.zoom * (magnifierOptions.largeWrapperW / magnifierOptions.w));\n                magnifierOptions.largeT = Math.round(magnifierOptions.lensBgY * magnifierOptions.zoom * (magnifierOptions.largeWrapperH / magnifierOptions.h));\n            }\n        }\n\n        function onThumbEnter() {\n            if (_toBoolean(enabled)) {\n                magnifierOptions = data[curIdx];\n                curLens = $box.find('.magnify-lens');\n\n                if (magnifierOptions.status === 2) {\n                    curLens.removeClass(MagnifyCls.magnifyOpaque);\n                    curLarge = $('#' + curIdx + '-large');\n                    curLarge.removeClass(MagnifyCls.magnifyHidden);\n                } else if (magnifierOptions.status === 1) {\n                    curLens.className = 'magnifier-loader';\n                }\n            }\n        }\n\n        function onThumbLeave() {\n            if (magnifierOptions.status > 0) {\n                var handler = magnifierOptions.onthumbleave;\n\n                if (handler !== null) {\n                    handler({\n                        thumb: curThumb,\n                        lens: curLens,\n                        large: curLarge,\n                        x: pos.x,\n                        y: pos.y\n                    });\n                }\n\n                if (!curLens.hasClass(MagnifyCls.magnifyHidden)) {\n                    curLens.addClass(MagnifyCls.magnifyHidden);\n\n                    //$curThumb.removeClass(MagnifyCls.magnifyOpaque);\n                    if (curLarge !== null) {\n                        curLarge.addClass(MagnifyCls.magnifyHidden);\n                    }\n                }\n            }\n        }\n\n        function move() {\n            if (_toBoolean(enabled)) {\n                if (status !== magnifierOptions.status) {\n                    onThumbEnter();\n                }\n\n                if (magnifierOptions.status > 0) {\n                    curThumb.className = magnifierOptions.thumbCssClass + ' magnify-opaque';\n\n                    if (magnifierOptions.status === 1) {\n                        curLens.className = 'magnifier-loader';\n                    } else if (magnifierOptions.status === 2) {\n                        curLens.removeClass(MagnifyCls.magnifyHidden);\n                        curLarge.removeClass(MagnifyCls.magnifyHidden);\n                        curLarge.css({\n                            left: '-' + magnifierOptions.largeL + 'px',\n                            top: '-' + magnifierOptions.largeT + 'px'\n                        });\n                    }\n\n                    var borderOffset = 2; // Offset for magnify-lens border\n                    pos.t = pos.t <= 0 ? 0 : pos.t - borderOffset;\n\n                    curLens.css({\n                        left: pos.l + paddingX + 'px',\n                        top: pos.t + paddingY + 'px'\n                    });\n\n                    if (lensbg) {\n                        curLens.css({\n                            'background-color': 'rgba(f,f,f,.5)'\n                        });\n                    } else {\n                        curLens.get(0).style.backgroundPosition = '-' +\n                        magnifierOptions.lensBgX + 'px -' +\n                        magnifierOptions.lensBgY + 'px';\n                    }\n                    var handler = magnifierOptions.onthumbmove;\n\n                    if (handler !== null) {\n                        handler({\n                            thumb: curThumb,\n                            lens: curLens,\n                            large: curLarge,\n                            x: pos.x,\n                            y: pos.y\n                        });\n                    }\n                }\n\n                status = magnifierOptions.status;\n            }\n        }\n\n        function setThumbData(mainImage, mainImageData) {\n            var thumbBounds = mainImage.getBoundingClientRect(),\n                w = 0,\n                h = 0;\n\n            mainImageData.x = Math.round(thumbBounds.left);\n            mainImageData.y = Math.round(thumbBounds.top);\n            mainImageData.w = Math.round(thumbBounds.right - mainImageData.x);\n            mainImageData.h = Math.round(thumbBounds.bottom - mainImageData.y);\n\n            if (mainImageData.mode === 'inside') {\n                w = mainImageData.w;\n                h = mainImageData.h;\n            } else {\n                w = mainImageData.largeWrapperW;\n                h = mainImageData.largeWrapperH;\n            }\n\n            mainImageData.largeImgInMagnifyLensWidth = Math.round(mainImageData.zoom * w);\n            mainImageData.largeImgInMagnifyLensHeight = Math.round(mainImageData.zoom * h);\n\n            mainImageData.lensW = Math.round(mainImageData.w / mainImageData.zoom);\n            mainImageData.lensH = Math.round(mainImageData.h / mainImageData.zoom);\n        }\n\n        function _init($box, options) {\n            var opts = {};\n\n            if (options.thumb === undefined) {\n                return false;\n            }\n\n            $thumb = $box.find(options.thumb);\n\n            if ($thumb.length) {\n                for (var key in options) {\n                    opts[key] = options[key];\n                }\n\n                opts.thumb = $thumb;\n                enabled = opts.enabled;\n\n                if (_toBoolean(enabled)) {\n\n                    $magnifierPreview.show().css('display', '');\n                    $magnifierPreview.addClass(MagnifyCls.magnifyHidden);\n                    set(opts);\n                } else {\n                    $magnifierPreview.empty().hide();\n                }\n            }\n\n            return that;\n        }\n\n        function hoverEvents(thumb) {\n            $(thumb).on('mouseover', function (e) {\n\n                if (showWrapper) {\n\n                    if (magnifierOptions.status !== 0) {\n                        onThumbLeave();\n                    }\n                    handleEvents(e);\n                    isOverThumb = inBounds;\n                }\n            }).trigger('mouseover');\n        }\n\n        function clickEvents(thumb) {\n            $(thumb).on('click', function (e) {\n\n                if (showWrapper) {\n                    if (!isOverThumb) {\n                        if (magnifierOptions.status !== 0) {\n                            onThumbLeave();\n                        }\n                        handleEvents(e);\n                        isOverThumb = true;\n                    }\n                }\n            });\n        }\n\n        function bindEvents(eType, thumb) {\n            var eventFlag = 'hasBoundEvent_' + eType;\n            if (thumb[eventFlag]) {\n                // Events are already bound, no need to bind in duplicate\n                return;\n            }\n            thumb[eventFlag] = true;\n\n            switch (eType) {\n                case 'hover':\n                    hoverEvents(thumb);\n                    break;\n\n                case 'click':\n                    clickEvents(thumb);\n                    break;\n            }\n        }\n\n        function handleEvents(e) {\n            var src = e.target;\n\n            curIdx = src.id;\n            curThumb = src;\n\n            onThumbEnter(src);\n\n            setThumbData(curThumb, magnifierOptions);\n\n            pos.x = e.clientX;\n            pos.y = e.clientY;\n\n            getMousePos();\n            move();\n\n            var handler = magnifierOptions.onthumbenter;\n\n            if (handler !== null) {\n                handler({\n                    thumb: curThumb,\n                    lens: curLens,\n                    large: curLarge,\n                    x: pos.x,\n                    y: pos.y\n                });\n            }\n        }\n\n        function set(options) {\n            if (data[options.thumb.id] !== undefined) {\n                curThumb = options.thumb;\n\n                return false;\n            }\n\n            var thumbObj = new Image(),\n                largeObj = new Image(),\n                $thumb = options.thumb,\n                thumb = $thumb.get(0),\n                idx = thumb.id,\n                largeUrl,\n                largeWrapper = $(options.largeWrapper),\n                zoom = options.zoom || thumb.getAttribute('data-zoom') || gZoom,\n                zoomMin = options.zoomMin || gZoomMin,\n                zoomMax = options.zoomMax || gZoomMax,\n                mode = options.mode || thumb.getAttribute('data-mode') || gMode,\n                eventType = options.eventType || thumb.getAttribute('data-eventType') || gEventType,\n                onthumbenter = options.onthumbenter !== undefined ?\n                    options.onthumbenter\n                    : magnifierOptions.onthumbenter,\n                onthumbleave = options.onthumbleave !== undefined ?\n                    options.onthumbleave\n                    : magnifierOptions.onthumbleave,\n                onthumbmove = options.onthumbmove !== undefined ?\n                    options.onthumbmove\n                    : magnifierOptions.onthumbmove;\n\n            largeUrl = $thumb.data('original') || customUserOptions.full || $thumb.attr('src');\n\n            if (thumb.id === '') {\n                idx = thumb.id = 'magnifier-item-' + gId;\n                gId += 1;\n            }\n\n            createLens(thumb, idx);\n\n            if (options.width) {\n                largeWrapper.width(options.width);\n            }\n\n            if (options.height) {\n                largeWrapper.height(options.height);\n            }\n\n            if (options.top) {\n                if (typeof options.top == 'function') {\n                    var top = options.top() + 'px';\n                } else {\n                    var top = options.top + 'px';\n                }\n\n                if (largeWrapper.length) {\n                    largeWrapper[0].style.top = top.replace('%px', '%');\n                }\n            }\n\n            if (options.left) {\n                if (typeof options.left == 'function') {\n                    var left = options.left() + 'px';\n                } else {\n                    var left = options.left + 'px';\n                }\n\n                if (largeWrapper.length) {\n                    largeWrapper[0].style.left = left.replace('%px', '%');\n                }\n            }\n\n            data[idx] = {\n                zoom: zoom,\n                zoomMin: zoomMin,\n                zoomMax: zoomMax,\n                mode: mode,\n                eventType: eventType,\n                thumbCssClass: thumb.className,\n                zoomAttached: false,\n                status: 0,\n                largeUrl: largeUrl,\n                largeWrapperId: mode === 'outside' ? largeWrapper.attr('id') : null,\n                largeWrapperW: mode === 'outside' ? largeWrapper.width() : null,\n                largeWrapperH: mode === 'outside' ? largeWrapper.height() : null,\n                onthumbenter: onthumbenter,\n                onthumbleave: onthumbleave,\n                onthumbmove: onthumbmove\n            };\n\n            paddingX = ($thumb.parent().width() - $thumb.width()) / 2;\n            paddingY = ($thumb.parent().height() - $thumb.height()) / 2;\n\n            showWrapper = false;\n            $(thumbObj).on('load', function () {\n                if (data.length > 0) {\n                    data[idx].status = 1;\n\n                    $(largeObj).on('load', function () {\n\n                        if (largeObj.width > largeWrapper.width() || largeObj.height > largeWrapper.height()) {\n                            showWrapper = true;\n                            bindEvents(eventType, thumb);\n                            data[idx].status = 2;\n                            if (largeObj.width > largeObj.height) {\n                                data[idx].zoom = largeObj.width / largeWrapper.width();\n                            } else {\n                                data[idx].zoom = largeObj.height / largeWrapper.height();\n                            }\n                            setThumbData(thumb, data[idx]);\n                            updateLensOnLoad(idx, thumb, largeObj, largeWrapper);\n                        }\n                    });\n\n                    largeObj.src = data[idx].largeUrl;\n                }\n            });\n\n            thumbObj.src = thumb.src;\n        }\n\n        /**\n         * Hide magnifier when mouse exceeds image bounds.\n         */\n        function onMouseLeave() {\n            onThumbLeave();\n            isOverThumb = false;\n            $magnifierPreview.addClass(MagnifyCls.magnifyHidden);\n        }\n\n        function onMousemove(e) {\n            pos.x = e.clientX;\n            pos.y = e.clientY;\n\n            getMousePos();\n\n            if (gEventType === 'hover') {\n                isOverThumb = inBounds;\n            }\n\n            if (inBounds && isOverThumb) {\n                if (gMode === 'outside') {\n                    $magnifierPreview.removeClass(MagnifyCls.magnifyHidden);\n                }\n                move();\n            }\n        }\n\n        function onScroll() {\n            if (curThumb !== null) {\n                setThumbData(curThumb, magnifierOptions);\n            }\n        }\n\n        $(window).on('scroll', onScroll);\n        $(window).on('resize', function () {\n            _init($box, customUserOptions);\n        });\n\n        $box.on('mousemove', onMousemove);\n        $box.on('mouseleave', onMouseLeave);\n\n        _init($box, customUserOptions);\n    }\n}(jQuery));\n","knockoutjs/knockout-es5.js":"/*!\n * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5\n * Copyright (c) Steve Sanderson\n * MIT license\n */\n\n(function(global, undefined) {\n  'use strict';\n\n  var ko;\n\n  // Model tracking\n  // --------------\n  //\n  // This is the central feature of Knockout-ES5. We augment model objects by converting properties\n  // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can\n  // use plain JavaScript syntax to read/write the property while still getting the full benefits of\n  // Knockout's automatic dependency detection and notification triggering.\n  //\n  // For comparison, here's Knockout ES3-compatible syntax:\n  //\n  //     var firstNameLength = myModel.user().firstName().length; // Read\n  //     myModel.user().firstName('Bert'); // Write\n  //\n  // ... versus Knockout-ES5 syntax:\n  //\n  //     var firstNameLength = myModel.user.firstName.length; // Read\n  //     myModel.user.firstName = 'Bert'; // Write\n\n  // `ko.track(model)` converts each property on the given model object into a getter/setter pair that\n  // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we\n  // wrap all properties. If any of the properties are already observables, we replace them with\n  // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly\n  // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored,\n  // which is how ES5 readonly properties normally behave).\n  //\n  // By design, this does *not* recursively walk child object properties, because making literally\n  // everything everywhere independently observable is usually unhelpful. When you do want to track\n  // child object properties independently, define your own class for those child objects and put\n  // a separate ko.track call into its constructor --- this gives you far more control.\n  /**\n   * @param {object} obj\n   * @param {object|array.<string>} propertyNamesOrSettings\n   * @param {boolean} propertyNamesOrSettings.deep Use deep track.\n   * @param {array.<string>} propertyNamesOrSettings.fields Array of property names to wrap.\n   * todo: @param {array.<string>} propertyNamesOrSettings.exclude Array of exclude property names to wrap.\n   * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property \n   *   names to wrap. A function that takes ... params\n   * @return {object}\n   */\n  function track(obj, propertyNamesOrSettings) {\n    if (!obj || typeof obj !== 'object') {\n      throw new Error('When calling ko.track, you must pass an object as the first parameter.');\n    }\n\n    var propertyNames;\n\n    if ( isPlainObject(propertyNamesOrSettings) ) {\n      // defaults\n      propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false;\n      propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj);\n      propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false;\n\n      wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings);\n    } else {\n      propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj);\n      wrap(obj, propertyNames, {});\n    }\n\n    return obj;\n  }\n\n  // fix for ie\n  var rFunctionName = /^function\\s*([^\\s(]+)/;\n  function getFunctionName( ctor ){\n    if (ctor.name) {\n      return ctor.name;\n    }\n    return (ctor.toString().trim().match( rFunctionName ) || [])[1];\n  }\n\n  function canTrack(obj) {\n    return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object';\n  }\n\n  function createPropertyDescriptor(originalValue, prop, map) {\n    var isObservable = ko.isObservable(originalValue);\n    var isArray = !isObservable && Array.isArray(originalValue);\n    var observable = isObservable ? originalValue\n        : isArray ? ko.observableArray(originalValue)\n        : ko.observable(originalValue);\n\n    map[prop] = function () { return observable; };\n\n    // add check in case the object is already an observable array\n    if (isArray || (isObservable && 'push' in observable)) {\n      notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n    }\n\n    return {\n      configurable: true,\n      enumerable: true,\n      get: observable,\n      set: ko.isWriteableObservable(observable) ? observable : undefined\n    };\n  }\n\n  function createLazyPropertyDescriptor(originalValue, prop, map) {\n    if (ko.isObservable(originalValue)) {\n      // no need to be lazy if we already have an observable\n      return createPropertyDescriptor(originalValue, prop, map);\n    }\n\n    var observable;\n\n    function getOrCreateObservable(value, writing) {\n      if (observable) {\n        return writing ? observable(value) : observable;\n      }\n\n      if (Array.isArray(value)) {\n        observable = ko.observableArray(value);\n        notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n        return observable;\n      }\n\n      return (observable = ko.observable(value));\n    }\n\n    map[prop] = function () { return getOrCreateObservable(originalValue); };\n    return {\n      configurable: true,\n      enumerable: true,\n      get: function () { return getOrCreateObservable(originalValue)(); },\n      set: function (value) { getOrCreateObservable(value, true); }\n    };\n  }\n\n  function wrap(obj, props, options) {\n    if (!props.length) {\n      return;\n    }\n\n    var allObservablesForObject = getAllObservablesForObject(obj, true);\n    var descriptors = {};\n\n    props.forEach(function (prop) {\n      // Skip properties that are already tracked\n      if (prop in allObservablesForObject) {\n        return;\n      }\n\n      // Skip properties where descriptor can't be redefined\n      if (Object.getOwnPropertyDescriptor(obj, prop).configurable === false){\n        return;\n      }\n\n      var originalValue = obj[prop];\n      descriptors[prop] = (options.lazy ? createLazyPropertyDescriptor : createPropertyDescriptor)\n        (originalValue, prop, allObservablesForObject);\n\n      if (options.deep && canTrack(originalValue)) {\n        wrap(originalValue, Object.keys(originalValue), options);\n      }\n    });\n\n    Object.defineProperties(obj, descriptors);\n  }\n\n  function isPlainObject( obj ){\n    return !!obj && typeof obj === 'object' && obj.constructor === Object;\n  }\n\n  // Lazily created by `getAllObservablesForObject` below. Has to be created lazily because the\n  // WeakMap factory isn't available until the module has finished loading (may be async).\n  var objectToObservableMap;\n\n  // Gets or creates the hidden internal key-value collection of observables corresponding to\n  // properties on the model object.\n  function getAllObservablesForObject(obj, createIfNotDefined) {\n    if (!objectToObservableMap) {\n      objectToObservableMap = weakMapFactory();\n    }\n\n    var result = objectToObservableMap.get(obj);\n    if (!result && createIfNotDefined) {\n      result = {};\n      objectToObservableMap.set(obj, result);\n    }\n    return result;\n  }\n\n  // Removes the internal references to observables mapped to the specified properties\n  // or the entire object reference if no properties are passed in. This allows the\n  // observables to be replaced and tracked again.\n  function untrack(obj, propertyNames) {\n    if (!objectToObservableMap) {\n      return;\n    }\n\n    if (arguments.length === 1) {\n      objectToObservableMap['delete'](obj);\n    } else {\n      var allObservablesForObject = getAllObservablesForObject(obj, false);\n      if (allObservablesForObject) {\n        propertyNames.forEach(function(propertyName) {\n          delete allObservablesForObject[propertyName];\n        });\n      }\n    }\n  }\n\n  // Computed properties\n  // -------------------\n  //\n  // The preceding code is already sufficient to upgrade ko.computed model properties to ES5\n  // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter).\n  // These then behave like a regular property with a getter function, except they are smarter:\n  // your evaluator is only invoked when one of its dependencies changes. The result is cached\n  // and used for all evaluations until the next time a dependency changes).\n  //\n  // However, instead of forcing developers to declare a ko.computed property explicitly, it's\n  // nice to offer a utility function that declares a computed getter directly.\n\n  // Implements `ko.defineProperty`\n  function defineComputedProperty(obj, propertyName, evaluatorOrOptions) {\n    var ko = this,\n      computedOptions = { owner: obj, deferEvaluation: true };\n\n    if (typeof evaluatorOrOptions === 'function') {\n      computedOptions.read = evaluatorOrOptions;\n    } else {\n      if ('value' in evaluatorOrOptions) {\n        throw new Error('For ko.defineProperty, you must not specify a \"value\" for the property. ' +\n                        'You must provide a \"get\" function.');\n      }\n\n      if (typeof evaluatorOrOptions.get !== 'function') {\n        throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, ' +\n                        'or an options object containing a function called \"get\".');\n      }\n\n      computedOptions.read = evaluatorOrOptions.get;\n      computedOptions.write = evaluatorOrOptions.set;\n    }\n\n    obj[propertyName] = ko.computed(computedOptions);\n    track.call(ko, obj, [propertyName]);\n    return obj;\n  }\n\n  // Array handling\n  // --------------\n  //\n  // Arrays are special, because unlike other property types, they have standard mutator functions\n  // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of\n  // those mutator functions is invoked.\n  //\n  // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable\n  // arrays that mutate the underlying array and then trigger a notification. That approach doesn't\n  // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs\n  // in the context of the underlying array, not any particular observable:\n  //\n  //     // Operates on the underlying array value\n  //     myModel.someCollection.push('New value');\n  //\n  // To solve this, Knockout-ES5 detects array values, and modifies them as follows:\n  //  1. Associates a hidden subscribable with each array instance that it encounters\n  //  2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable\n  // Then, for model properties whose values are arrays, the property's underlying observable\n  // subscribes to the array subscribable, so it can trigger a change notification after mutation.\n\n  // Given an observable that underlies a model property, watch for any array value that might\n  // be assigned as the property value, and hook into its change events\n  function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) {\n    var watchingArraySubscription = null;\n    ko.computed(function () {\n      // Unsubscribe to any earlier array instance\n      if (watchingArraySubscription) {\n        watchingArraySubscription.dispose();\n        watchingArraySubscription = null;\n      }\n\n      // Subscribe to the new array instance\n      var newArrayInstance = observable();\n      if (newArrayInstance instanceof Array) {\n        watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance);\n      }\n    });\n  }\n\n  // Listens for array mutations, and when they happen, cause the observable to fire notifications.\n  // This is used to make model properties of type array fire notifications when the array changes.\n  // Returns a subscribable that can later be disposed.\n  function startWatchingArrayInstance(ko, observable, arrayInstance) {\n    var subscribable = getSubscribableForArray(ko, arrayInstance);\n    return subscribable.subscribe(observable);\n  }\n\n  // Lazily created by `getSubscribableForArray` below. Has to be created lazily because the\n  // WeakMap factory isn't available until the module has finished loading (may be async).\n  var arraySubscribablesMap;\n\n  // Gets or creates a subscribable that fires after each array mutation\n  function getSubscribableForArray(ko, arrayInstance) {\n    if (!arraySubscribablesMap) {\n      arraySubscribablesMap = weakMapFactory();\n    }\n\n    var subscribable = arraySubscribablesMap.get(arrayInstance);\n    if (!subscribable) {\n      subscribable = new ko.subscribable();\n      arraySubscribablesMap.set(arrayInstance, subscribable);\n\n      var notificationPauseSignal = {};\n      wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal);\n      addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal);\n    }\n\n    return subscribable;\n  }\n\n  // After each array mutation, fires a notification on the given subscribable\n  function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) {\n    ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) {\n      var origMutator = arrayInstance[fnName];\n      arrayInstance[fnName] = function() {\n        var result = origMutator.apply(this, arguments);\n        if (notificationPauseSignal.pause !== true) {\n          subscribable.notifySubscribers(this);\n        }\n        return result;\n      };\n    });\n  }\n\n  // Adds Knockout's additional array mutation functions to the array\n  function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) {\n    ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) {\n      // Make it a non-enumerable property for consistency with standard Array functions\n      Object.defineProperty(arrayInstance, fnName, {\n        enumerable: false,\n        value: function() {\n          var result;\n\n          // These additional array mutators are built using the underlying push/pop/etc.\n          // mutators, which are wrapped to trigger notifications. But we don't want to\n          // trigger multiple notifications, so pause the push/pop/etc. wrappers and\n          // delivery only one notification at the end of the process.\n          notificationPauseSignal.pause = true;\n          try {\n            // Creates a temporary observableArray that can perform the operation.\n            result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments);\n          }\n          finally {\n            notificationPauseSignal.pause = false;\n          }\n          subscribable.notifySubscribers(arrayInstance);\n          return result;\n        }\n      });\n    });\n  }\n\n  // Static utility functions\n  // ------------------------\n  //\n  // Since Knockout-ES5 sets up properties that return values, not observables, you can't\n  // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`),\n  // or tell them that object values have mutated, etc. To handle this, we set up some\n  // extra utility functions that can return or work with the underlying observables.\n\n  // Returns the underlying observable associated with a model property (or `null` if the\n  // model or property doesn't exist, or isn't associated with an observable). This means\n  // you can subscribe to the property, e.g.:\n  //\n  //     ko.getObservable(model, 'propertyName')\n  //       .subscribe(function(newValue) { ... });\n  function getObservable(obj, propertyName) {\n    if (!obj || typeof obj !== 'object') {\n      return null;\n    }\n\n    var allObservablesForObject = getAllObservablesForObject(obj, false);\n    if (allObservablesForObject && propertyName in allObservablesForObject) {\n      return allObservablesForObject[propertyName]();\n    }\n\n    return null;\n  }\n  \n  // Returns a boolean indicating whether the property on the object has an underlying\n  // observables. This does the check in a way not to create an observable if the\n  // object was created with lazily created observables\n  function isTracked(obj, propertyName) {\n    if (!obj || typeof obj !== 'object') {\n      return false;\n    }\n    \n    var allObservablesForObject = getAllObservablesForObject(obj, false);\n    return !!allObservablesForObject && propertyName in allObservablesForObject;\n  }\n\n  // Causes a property's associated observable to fire a change notification. Useful when\n  // the property value is a complex object and you've modified a child property.\n  function valueHasMutated(obj, propertyName) {\n    var observable = getObservable(obj, propertyName);\n\n    if (observable) {\n      observable.valueHasMutated();\n    }\n  }\n\n  // Module initialisation\n  // ---------------------\n  //\n  // When this script is first evaluated, it works out what kind of module loading scenario\n  // it is in (Node.js or a browser `<script>` tag), stashes a reference to its dependencies\n  // (currently that's just the WeakMap shim), and then finally attaches itself to whichever\n  // instance of Knockout.js it can find.\n\n  // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed).\n  // Instantiated by prepareExports, accounting for which module loader is being used.\n  var weakMapFactory;\n\n  // Extends a Knockout instance with Knockout-ES5 functionality\n  function attachToKo(ko) {\n    ko.track = track;\n    ko.untrack = untrack;\n    ko.getObservable = getObservable;\n    ko.valueHasMutated = valueHasMutated;\n    ko.defineProperty = defineComputedProperty;\n\n    // todo: test it, maybe added it to ko. directly\n    ko.es5 = {\n      getAllObservablesForObject: getAllObservablesForObject,\n      notifyWhenPresentOrFutureArrayValuesMutate: notifyWhenPresentOrFutureArrayValuesMutate,\n      isTracked: isTracked\n    };\n  }\n\n  // Determines which module loading scenario we're in, grabs dependencies, and attaches to KO\n  function prepareExports() {\n    if (typeof exports === 'object' && typeof module === 'object') {\n      // Node.js case - load KO and WeakMap modules synchronously\n      ko = require('knockout');\n      var WM = require('../lib/weakmap');\n      attachToKo(ko);\n      weakMapFactory = function() { return new WM(); };\n      module.exports = ko;\n    } else if (typeof define === 'function' && define.amd) {\n      define(['knockout'], function(koModule) {\n        ko = koModule;\n        attachToKo(koModule);\n        weakMapFactory = function() { return new global.WeakMap(); };\n        return koModule;\n      });\n    } else if ('ko' in global) {\n      // Non-module case - attach to the global instance, and assume a global WeakMap constructor\n      ko = global.ko;\n      attachToKo(global.ko);\n      weakMapFactory = function() { return new global.WeakMap(); };\n    }\n  }\n\n  prepareExports();\n\n})(this);","knockoutjs/knockout.js":"/*!\n * Knockout JavaScript library v3.5.1\n * (c) The Knockout.js team - http://knockoutjs.com/\n * License: MIT (http://www.opensource.org/licenses/mit-license.php)\n */\n\n(function(){\n    var DEBUG=true;\n    (function(undefined){\n        // (0, eval)('this') is a robust way of getting a reference to the global object\n        // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023\n        var window = this || (0, eval)('this'),\n            document = window['document'],\n            navigator = window['navigator'],\n            jQueryInstance = window[\"jQuery\"],\n            JSON = window[\"JSON\"];\n\n        if (!jQueryInstance && typeof jQuery !== \"undefined\") {\n            jQueryInstance = jQuery;\n        }\n        (function(factory) {\n            // Support three module loading scenarios\n            if (typeof define === 'function' && define['amd']) {\n                // [1] AMD anonymous module\n                define(['exports', 'require'], factory);\n            } else if (typeof exports === 'object' && typeof module === 'object') {\n                // [2] CommonJS/Node.js\n                factory(module['exports'] || exports);  // module.exports is for Node.js\n            } else {\n                // [3] No module loader (plain <script> tag) - put directly in global namespace\n                factory(window['ko'] = {});\n            }\n        }(function(koExports, amdRequire){\n// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).\n// In the future, the following \"ko\" variable may be made distinct from \"koExports\" so that private objects are not externally reachable.\n            var ko = typeof koExports !== 'undefined' ? koExports : {};\n// Google Closure Compiler helpers (used only to make the minified file smaller)\n            ko.exportSymbol = function(koPath, object) {\n                var tokens = koPath.split(\".\");\n\n                // In the future, \"ko\" may become distinct from \"koExports\" (so that non-exported objects are not reachable)\n                // At that point, \"target\" would be set to: (typeof koExports !== \"undefined\" ? koExports : ko)\n                var target = ko;\n\n                for (var i = 0; i < tokens.length - 1; i++)\n                    target = target[tokens[i]];\n                target[tokens[tokens.length - 1]] = object;\n            };\n            ko.exportProperty = function(owner, publicName, object) {\n                owner[publicName] = object;\n            };\n            ko.version = \"3.5.1\";\n\n            ko.exportSymbol('version', ko.version);\n// For any options that may affect various areas of Knockout and aren't directly associated with data binding.\n            ko.options = {\n                'deferUpdates': false,\n                'useOnlyNativeEvents': false,\n                'foreachHidesDestroyed': false\n            };\n\n//ko.exportSymbol('options', ko.options);   // 'options' isn't minified\n            ko.utils = (function () {\n                var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n                function objectForEach(obj, action) {\n                    for (var prop in obj) {\n                        if (hasOwnProperty.call(obj, prop)) {\n                            action(prop, obj[prop]);\n                        }\n                    }\n                }\n\n                function extend(target, source) {\n                    if (source) {\n                        for(var prop in source) {\n                            if(hasOwnProperty.call(source, prop)) {\n                                target[prop] = source[prop];\n                            }\n                        }\n                    }\n                    return target;\n                }\n\n                function setPrototypeOf(obj, proto) {\n                    obj.__proto__ = proto;\n                    return obj;\n                }\n\n                var canSetPrototype = ({ __proto__: [] } instanceof Array);\n                var canUseSymbols = !DEBUG && typeof Symbol === 'function';\n\n                // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)\n                var knownEvents = {}, knownEventTypesByEventName = {};\n                var keyEventTypeName = (navigator && /Firefox\\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';\n                knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];\n                knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];\n                objectForEach(knownEvents, function(eventType, knownEventsForType) {\n                    if (knownEventsForType.length) {\n                        for (var i = 0, j = knownEventsForType.length; i < j; i++)\n                            knownEventTypesByEventName[knownEventsForType[i]] = eventType;\n                    }\n                });\n                var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406\n\n                // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)\n                // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.\n                // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.\n                // If there is a future need to detect specific versions of IE10+, we will amend this.\n                var ieVersion = document && (function() {\n                    var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');\n\n                    // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment\n                    while (\n                        div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',\n                            iElems[0]\n                        ) {}\n                    return version > 4 ? version : undefined;\n                }());\n                var isIe6 = ieVersion === 6,\n                    isIe7 = ieVersion === 7;\n\n                function isClickOnCheckableElement(element, eventType) {\n                    if ((ko.utils.tagNameLower(element) !== \"input\") || !element.type) return false;\n                    if (eventType.toLowerCase() != \"click\") return false;\n                    var inputType = element.type;\n                    return (inputType == \"checkbox\") || (inputType == \"radio\");\n                }\n\n                // For details on the pattern for changing node classes\n                // see: https://github.com/knockout/knockout/issues/1597\n                var cssClassNameRegex = /\\S+/g;\n\n                var jQueryEventAttachName;\n\n                function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {\n                    var addOrRemoveFn;\n                    if (classNames) {\n                        if (typeof node.classList === 'object') {\n                            addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];\n                            ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                                addOrRemoveFn.call(node.classList, className);\n                            });\n                        } else if (typeof node.className['baseVal'] === 'string') {\n                            // SVG tag .classNames is an SVGAnimatedString instance\n                            toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);\n                        } else {\n                            // node.className ought to be a string.\n                            toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);\n                        }\n                    }\n                }\n\n                function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {\n                    // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.\n                    var currentClassNames = obj[prop].match(cssClassNameRegex) || [];\n                    ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                        ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);\n                    });\n                    obj[prop] = currentClassNames.join(\" \");\n                }\n\n                return {\n                    fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],\n\n                    arrayForEach: function (array, action, actionOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            action.call(actionOwner, array[i], i, array);\n                        }\n                    },\n\n                    arrayIndexOf: typeof Array.prototype.indexOf == \"function\"\n                        ? function (array, item) {\n                            return Array.prototype.indexOf.call(array, item);\n                        }\n                        : function (array, item) {\n                            for (var i = 0, j = array.length; i < j; i++) {\n                                if (array[i] === item)\n                                    return i;\n                            }\n                            return -1;\n                        },\n\n                    arrayFirst: function (array, predicate, predicateOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            if (predicate.call(predicateOwner, array[i], i, array))\n                                return array[i];\n                        }\n                        return undefined;\n                    },\n\n                    arrayRemoveItem: function (array, itemToRemove) {\n                        var index = ko.utils.arrayIndexOf(array, itemToRemove);\n                        if (index > 0) {\n                            array.splice(index, 1);\n                        }\n                        else if (index === 0) {\n                            array.shift();\n                        }\n                    },\n\n                    arrayGetDistinctValues: function (array) {\n                        var result = [];\n                        if (array) {\n                            ko.utils.arrayForEach(array, function(item) {\n                                if (ko.utils.arrayIndexOf(result, item) < 0)\n                                    result.push(item);\n                            });\n                        }\n                        return result;\n                    },\n\n                    arrayMap: function (array, mapping, mappingOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                result.push(mapping.call(mappingOwner, array[i], i));\n                        }\n                        return result;\n                    },\n\n                    arrayFilter: function (array, predicate, predicateOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                if (predicate.call(predicateOwner, array[i], i))\n                                    result.push(array[i]);\n                        }\n                        return result;\n                    },\n\n                    arrayPushAll: function (array, valuesToPush) {\n                        if (valuesToPush instanceof Array)\n                            array.push.apply(array, valuesToPush);\n                        else\n                            for (var i = 0, j = valuesToPush.length; i < j; i++)\n                                array.push(valuesToPush[i]);\n                        return array;\n                    },\n\n                    addOrRemoveItem: function(array, value, included) {\n                        var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);\n                        if (existingEntryIndex < 0) {\n                            if (included)\n                                array.push(value);\n                        } else {\n                            if (!included)\n                                array.splice(existingEntryIndex, 1);\n                        }\n                    },\n\n                    canSetPrototype: canSetPrototype,\n\n                    extend: extend,\n\n                    setPrototypeOf: setPrototypeOf,\n\n                    setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,\n\n                    objectForEach: objectForEach,\n\n                    objectMap: function(source, mapping, mappingOwner) {\n                        if (!source)\n                            return source;\n                        var target = {};\n                        for (var prop in source) {\n                            if (hasOwnProperty.call(source, prop)) {\n                                target[prop] = mapping.call(mappingOwner, source[prop], prop, source);\n                            }\n                        }\n                        return target;\n                    },\n\n                    emptyDomNode: function (domNode) {\n                        while (domNode.firstChild) {\n                            ko.removeNode(domNode.firstChild);\n                        }\n                    },\n\n                    moveCleanedNodesToContainerElement: function(nodes) {\n                        // Ensure it's a real array, as we're about to reparent the nodes and\n                        // we don't want the underlying collection to change while we're doing that.\n                        var nodesArray = ko.utils.makeArray(nodes);\n                        var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;\n\n                        var container = templateDocument.createElement('div');\n                        for (var i = 0, j = nodesArray.length; i < j; i++) {\n                            container.appendChild(ko.cleanNode(nodesArray[i]));\n                        }\n                        return container;\n                    },\n\n                    cloneNodes: function (nodesArray, shouldCleanNodes) {\n                        for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {\n                            var clonedNode = nodesArray[i].cloneNode(true);\n                            newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);\n                        }\n                        return newNodesArray;\n                    },\n\n                    setDomNodeChildren: function (domNode, childNodes) {\n                        ko.utils.emptyDomNode(domNode);\n                        if (childNodes) {\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                domNode.appendChild(childNodes[i]);\n                        }\n                    },\n\n                    replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {\n                        var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;\n                        if (nodesToReplaceArray.length > 0) {\n                            var insertionPoint = nodesToReplaceArray[0];\n                            var parent = insertionPoint.parentNode;\n                            for (var i = 0, j = newNodesArray.length; i < j; i++)\n                                parent.insertBefore(newNodesArray[i], insertionPoint);\n                            for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {\n                                ko.removeNode(nodesToReplaceArray[i]);\n                            }\n                        }\n                    },\n\n                    fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {\n                        // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile\n                        // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that\n                        // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been\n                        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.\n                        // So, this function translates the old \"map\" output array into its best guess of the set of current DOM nodes.\n                        //\n                        // Rules:\n                        //   [A] Any leading nodes that have been removed should be ignored\n                        //       These most likely correspond to memoization nodes that were already removed during binding\n                        //       See https://github.com/knockout/knockout/pull/440\n                        //   [B] Any trailing nodes that have been remove should be ignored\n                        //       This prevents the code here from adding unrelated nodes to the array while processing rule [C]\n                        //       See https://github.com/knockout/knockout/pull/1903\n                        //   [C] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,\n                        //       and include any nodes that have been inserted among the previous collection\n\n                        if (continuousNodeArray.length) {\n                            // The parent node can be a virtual element; so get the real parent node\n                            parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;\n\n                            // Rule [A]\n                            while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)\n                                continuousNodeArray.splice(0, 1);\n\n                            // Rule [B]\n                            while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)\n                                continuousNodeArray.length--;\n\n                            // Rule [C]\n                            if (continuousNodeArray.length > 1) {\n                                var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];\n                                // Replace with the actual new continuous node set\n                                continuousNodeArray.length = 0;\n                                while (current !== last) {\n                                    continuousNodeArray.push(current);\n                                    current = current.nextSibling;\n                                }\n                                continuousNodeArray.push(last);\n                            }\n                        }\n                        return continuousNodeArray;\n                    },\n\n                    setOptionNodeSelectionState: function (optionNode, isSelected) {\n                        // IE6 sometimes throws \"unknown error\" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.\n                        if (ieVersion < 7)\n                            optionNode.setAttribute(\"selected\", isSelected);\n                        else\n                            optionNode.selected = isSelected;\n                    },\n\n                    stringTrim: function (string) {\n                        return string === null || string === undefined ? '' :\n                            string.trim ?\n                                string.trim() :\n                                string.toString().replace(/^[\\s\\xa0]+|[\\s\\xa0]+$/g, '');\n                    },\n\n                    stringStartsWith: function (string, startsWith) {\n                        string = string || \"\";\n                        if (startsWith.length > string.length)\n                            return false;\n                        return string.substring(0, startsWith.length) === startsWith;\n                    },\n\n                    domNodeIsContainedBy: function (node, containedByNode) {\n                        if (node === containedByNode)\n                            return true;\n                        if (node.nodeType === 11)\n                            return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8\n                        if (containedByNode.contains)\n                            return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node);\n                        if (containedByNode.compareDocumentPosition)\n                            return (containedByNode.compareDocumentPosition(node) & 16) == 16;\n                        while (node && node != containedByNode) {\n                            node = node.parentNode;\n                        }\n                        return !!node;\n                    },\n\n                    domNodeIsAttachedToDocument: function (node) {\n                        return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);\n                    },\n\n                    anyDomNodeIsAttachedToDocument: function(nodes) {\n                        return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);\n                    },\n\n                    tagNameLower: function(element) {\n                        // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.\n                        // Possible future optimization: If we know it's an element from an XHTML document (not HTML),\n                        // we don't need to do the .toLowerCase() as it will always be lower case anyway.\n                        return element && element.tagName && element.tagName.toLowerCase();\n                    },\n\n                    catchFunctionErrors: function (delegate) {\n                        return ko['onError'] ? function () {\n                            try {\n                                return delegate.apply(this, arguments);\n                            } catch (e) {\n                                ko['onError'] && ko['onError'](e);\n                                throw e;\n                            }\n                        } : delegate;\n                    },\n\n                    setTimeout: function (handler, timeout) {\n                        return setTimeout(ko.utils.catchFunctionErrors(handler), timeout);\n                    },\n\n                    deferError: function (error) {\n                        setTimeout(function () {\n                            ko['onError'] && ko['onError'](error);\n                            throw error;\n                        }, 0);\n                    },\n\n                    registerEventHandler: function (element, eventType, handler) {\n                        var wrappedHandler = ko.utils.catchFunctionErrors(handler);\n\n                        var mustUseAttachEvent = eventsThatMustBeRegisteredUsingAttachEvent[eventType];\n                        if (!ko.options['useOnlyNativeEvents'] && !mustUseAttachEvent && jQueryInstance) {\n                            if (!jQueryEventAttachName) {\n                                jQueryEventAttachName = (typeof jQueryInstance(element)['on'] == 'function') ? 'on' : 'bind';\n                            }\n                            jQueryInstance(element)[jQueryEventAttachName](eventType, wrappedHandler);\n                        } else if (!mustUseAttachEvent && typeof element.addEventListener == \"function\")\n                            element.addEventListener(eventType, wrappedHandler, false);\n                        else if (typeof element.attachEvent != \"undefined\") {\n                            var attachEventHandler = function (event) { wrappedHandler.call(element, event); },\n                                attachEventName = \"on\" + eventType;\n                            element.attachEvent(attachEventName, attachEventHandler);\n\n                            // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)\n                            // so to avoid leaks, we have to remove them manually. See bug #856\n                            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {\n                                element.detachEvent(attachEventName, attachEventHandler);\n                            });\n                        } else\n                            throw new Error(\"Browser doesn't support addEventListener or attachEvent\");\n                    },\n\n                    triggerEvent: function (element, eventType) {\n                        if (!(element && element.nodeType))\n                            throw new Error(\"element must be a DOM node when calling triggerEvent\");\n\n                        // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the\n                        // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)\n                        // IE doesn't change the checked state when you trigger the click event using \"fireEvent\".\n                        // In both cases, we'll use the click method instead.\n                        var useClickWorkaround = isClickOnCheckableElement(element, eventType);\n\n                        if (!ko.options['useOnlyNativeEvents'] && jQueryInstance && !useClickWorkaround) {\n                            jQueryInstance(element)['trigger'](eventType);\n                        } else if (typeof document.createEvent == \"function\") {\n                            if (typeof element.dispatchEvent == \"function\") {\n                                var eventCategory = knownEventTypesByEventName[eventType] || \"HTMLEvents\";\n                                var event = document.createEvent(eventCategory);\n                                event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);\n                                element.dispatchEvent(event);\n                            }\n                            else\n                                throw new Error(\"The supplied element doesn't support dispatchEvent\");\n                        } else if (useClickWorkaround && element.click) {\n                            element.click();\n                        } else if (typeof element.fireEvent != \"undefined\") {\n                            element.fireEvent(\"on\" + eventType);\n                        } else {\n                            throw new Error(\"Browser doesn't support triggering events\");\n                        }\n                    },\n\n                    unwrapObservable: function (value) {\n                        return ko.isObservable(value) ? value() : value;\n                    },\n\n                    peekObservable: function (value) {\n                        return ko.isObservable(value) ? value.peek() : value;\n                    },\n\n                    toggleDomNodeCssClass: toggleDomNodeCssClass,\n\n                    setTextContent: function(element, textContent) {\n                        var value = ko.utils.unwrapObservable(textContent);\n                        if ((value === null) || (value === undefined))\n                            value = \"\";\n\n                        // We need there to be exactly one child: a text node.\n                        // If there are no children, more than one, or if it's not a text node,\n                        // we'll clear everything and create a single text node.\n                        var innerTextNode = ko.virtualElements.firstChild(element);\n                        if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {\n                            ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);\n                        } else {\n                            innerTextNode.data = value;\n                        }\n\n                        ko.utils.forceRefresh(element);\n                    },\n\n                    setElementName: function(element, name) {\n                        element.name = name;\n\n                        // Workaround IE 6/7 issue\n                        // - https://github.com/SteveSanderson/knockout/issues/197\n                        // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/\n                        if (ieVersion <= 7) {\n                            try {\n                                var escapedName = element.name.replace(/[&<>'\"]/g, function(r){ return \"&#\" + r.charCodeAt(0) + \";\"; });\n                                element.mergeAttributes(document.createElement(\"<input name='\" + escapedName + \"'/>\"), false);\n                            }\n                            catch(e) {} // For IE9 with doc mode \"IE9 Standards\" and browser mode \"IE9 Compatibility View\"\n                        }\n                    },\n\n                    forceRefresh: function(node) {\n                        // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209\n                        if (ieVersion >= 9) {\n                            // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container\n                            var elem = node.nodeType == 1 ? node : node.parentNode;\n                            if (elem.style)\n                                elem.style.zoom = elem.style.zoom;\n                        }\n                    },\n\n                    ensureSelectElementIsRenderedCorrectly: function(selectElement) {\n                        // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.\n                        // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)\n                        // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)\n                        if (ieVersion) {\n                            var originalWidth = selectElement.style.width;\n                            selectElement.style.width = 0;\n                            selectElement.style.width = originalWidth;\n                        }\n                    },\n\n                    range: function (min, max) {\n                        min = ko.utils.unwrapObservable(min);\n                        max = ko.utils.unwrapObservable(max);\n                        var result = [];\n                        for (var i = min; i <= max; i++)\n                            result.push(i);\n                        return result;\n                    },\n\n                    makeArray: function(arrayLikeObject) {\n                        var result = [];\n                        for (var i = 0, j = arrayLikeObject.length; i < j; i++) {\n                            result.push(arrayLikeObject[i]);\n                        };\n                        return result;\n                    },\n\n                    createSymbolOrString: function(identifier) {\n                        return canUseSymbols ? Symbol(identifier) : identifier;\n                    },\n\n                    isIe6 : isIe6,\n                    isIe7 : isIe7,\n                    ieVersion : ieVersion,\n\n                    getFormFields: function(form, fieldName) {\n                        var fields = ko.utils.makeArray(form.getElementsByTagName(\"input\")).concat(ko.utils.makeArray(form.getElementsByTagName(\"textarea\")));\n                        var isMatchingField = (typeof fieldName == 'string')\n                            ? function(field) { return field.name === fieldName }\n                            : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate\n                        var matches = [];\n                        for (var i = fields.length - 1; i >= 0; i--) {\n                            if (isMatchingField(fields[i]))\n                                matches.push(fields[i]);\n                        };\n                        return matches;\n                    },\n\n                    parseJson: function (jsonString) {\n                        if (typeof jsonString == \"string\") {\n                            jsonString = ko.utils.stringTrim(jsonString);\n                            if (jsonString) {\n                                if (JSON && JSON.parse) // Use native parsing where available\n                                    return JSON.parse(jsonString);\n                                return (new Function(\"return \" + jsonString))(); // Fallback on less safe parsing for older browsers\n                            }\n                        }\n                        return null;\n                    },\n\n                    stringifyJson: function (data, replacer, space) {   // replacer and space are optional\n                        if (!JSON || !JSON.stringify)\n                            throw new Error(\"Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js\");\n                        return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);\n                    },\n\n                    postJson: function (urlOrForm, data, options) {\n                        options = options || {};\n                        var params = options['params'] || {};\n                        var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;\n                        var url = urlOrForm;\n\n                        // If we were given a form, use its 'action' URL and pick out any requested field values\n                        if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === \"form\")) {\n                            var originalForm = urlOrForm;\n                            url = originalForm.action;\n                            for (var i = includeFields.length - 1; i >= 0; i--) {\n                                var fields = ko.utils.getFormFields(originalForm, includeFields[i]);\n                                for (var j = fields.length - 1; j >= 0; j--)\n                                    params[fields[j].name] = fields[j].value;\n                            }\n                        }\n\n                        data = ko.utils.unwrapObservable(data);\n                        var form = document.createElement(\"form\");\n                        form.style.display = \"none\";\n                        form.action = url;\n                        form.method = \"post\";\n                        for (var key in data) {\n                            // Since 'data' this is a model object, we include all properties including those inherited from its prototype\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));\n                            form.appendChild(input);\n                        }\n                        objectForEach(params, function(key, value) {\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = value;\n                            form.appendChild(input);\n                        });\n                        document.body.appendChild(form);\n                        options['submitter'] ? options['submitter'](form) : form.submit();\n                        setTimeout(function () { form.parentNode.removeChild(form); }, 0);\n                    }\n                }\n            }());\n\n            ko.exportSymbol('utils', ko.utils);\n            ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);\n            ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);\n            ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);\n            ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);\n            ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);\n            ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);\n            ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);\n            ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);\n            ko.exportSymbol('utils.cloneNodes', ko.utils.cloneNodes);\n            ko.exportSymbol('utils.createSymbolOrString', ko.utils.createSymbolOrString);\n            ko.exportSymbol('utils.extend', ko.utils.extend);\n            ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);\n            ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);\n            ko.exportSymbol('utils.objectMap', ko.utils.objectMap);\n            ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);\n            ko.exportSymbol('utils.postJson', ko.utils.postJson);\n            ko.exportSymbol('utils.parseJson', ko.utils.parseJson);\n            ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);\n            ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);\n            ko.exportSymbol('utils.range', ko.utils.range);\n            ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);\n            ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);\n            ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);\n            ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);\n            ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);\n            ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);\n            ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly\n\n            if (!Function.prototype['bind']) {\n                // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)\n                // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js\n                Function.prototype['bind'] = function (object) {\n                    var originalFunction = this;\n                    if (arguments.length === 1) {\n                        return function () {\n                            return originalFunction.apply(object, arguments);\n                        };\n                    } else {\n                        var partialArgs = Array.prototype.slice.call(arguments, 1);\n                        return function () {\n                            var args = partialArgs.slice(0);\n                            args.push.apply(args, arguments);\n                            return originalFunction.apply(object, args);\n                        };\n                    }\n                };\n            }\n\n            ko.utils.domData = new (function () {\n                var uniqueId = 0;\n                var dataStoreKeyExpandoPropertyName = \"__ko__\" + (new Date).getTime();\n                var dataStore = {};\n\n                var getDataForNode, clear;\n                if (!ko.utils.ieVersion) {\n                    // We considered using WeakMap, but it has a problem in IE 11 and Edge that prevents using\n                    // it cross-window, so instead we just store the data directly on the node.\n                    // See https://github.com/knockout/knockout/issues/2141\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataForNode = node[dataStoreKeyExpandoPropertyName];\n                        if (!dataForNode && createIfNotFound) {\n                            dataForNode = node[dataStoreKeyExpandoPropertyName] = {};\n                        }\n                        return dataForNode;\n                    };\n                    clear = function (node) {\n                        if (node[dataStoreKeyExpandoPropertyName]) {\n                            delete node[dataStoreKeyExpandoPropertyName];\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                } else {\n                    // Old IE versions have memory issues if you store objects on the node, so we use a\n                    // separate data storage and link to it from the node using a string key.\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== \"null\") && dataStore[dataStoreKey];\n                        if (!hasExistingDataStore) {\n                            if (!createIfNotFound)\n                                return undefined;\n                            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = \"ko\" + uniqueId++;\n                            dataStore[dataStoreKey] = {};\n                        }\n                        return dataStore[dataStoreKey];\n                    };\n                    clear = function (node) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        if (dataStoreKey) {\n                            delete dataStore[dataStoreKey];\n                            node[dataStoreKeyExpandoPropertyName] = null;\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                }\n\n                return {\n                    get: function (node, key) {\n                        var dataForNode = getDataForNode(node, false);\n                        return dataForNode && dataForNode[key];\n                    },\n                    set: function (node, key, value) {\n                        // Make sure we don't actually create a new domData key if we are actually deleting a value\n                        var dataForNode = getDataForNode(node, value !== undefined /* createIfNotFound */);\n                        dataForNode && (dataForNode[key] = value);\n                    },\n                    getOrSet: function (node, key, value) {\n                        var dataForNode = getDataForNode(node, true /* createIfNotFound */);\n                        return dataForNode[key] || (dataForNode[key] = value);\n                    },\n                    clear: clear,\n\n                    nextKey: function () {\n                        return (uniqueId++) + dataStoreKeyExpandoPropertyName;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.domData', ko.utils.domData);\n            ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully\n\n            ko.utils.domNodeDisposal = new (function () {\n                var domDataKey = ko.utils.domData.nextKey();\n                var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document\n                var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document\n\n                function getDisposeCallbacksCollection(node, createIfNotFound) {\n                    var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);\n                    if ((allDisposeCallbacks === undefined) && createIfNotFound) {\n                        allDisposeCallbacks = [];\n                        ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);\n                    }\n                    return allDisposeCallbacks;\n                }\n                function destroyCallbacksCollection(node) {\n                    ko.utils.domData.set(node, domDataKey, undefined);\n                }\n\n                function cleanSingleNode(node) {\n                    // Run all the dispose callbacks\n                    var callbacks = getDisposeCallbacksCollection(node, false);\n                    if (callbacks) {\n                        callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)\n                        for (var i = 0; i < callbacks.length; i++)\n                            callbacks[i](node);\n                    }\n\n                    // Erase the DOM data\n                    ko.utils.domData.clear(node);\n\n                    // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)\n                    ko.utils.domNodeDisposal[\"cleanExternalData\"](node);\n\n                    // Clear any immediate-child comment nodes, as these wouldn't have been found by\n                    // node.getElementsByTagName(\"*\") in cleanNode() (comment nodes aren't elements)\n                    if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                        cleanNodesInList(node.childNodes, true/*onlyComments*/);\n                    }\n                }\n\n                function cleanNodesInList(nodeList, onlyComments) {\n                    var cleanedNodes = [], lastCleanedNode;\n                    for (var i = 0; i < nodeList.length; i++) {\n                        if (!onlyComments || nodeList[i].nodeType === 8) {\n                            cleanSingleNode(cleanedNodes[cleanedNodes.length] = lastCleanedNode = nodeList[i]);\n                            if (nodeList[i] !== lastCleanedNode) {\n                                while (i-- && ko.utils.arrayIndexOf(cleanedNodes, nodeList[i]) == -1) {}\n                            }\n                        }\n                    }\n                }\n\n                return {\n                    addDisposeCallback : function(node, callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"Callback must be a function\");\n                        getDisposeCallbacksCollection(node, true).push(callback);\n                    },\n\n                    removeDisposeCallback : function(node, callback) {\n                        var callbacksCollection = getDisposeCallbacksCollection(node, false);\n                        if (callbacksCollection) {\n                            ko.utils.arrayRemoveItem(callbacksCollection, callback);\n                            if (callbacksCollection.length == 0)\n                                destroyCallbacksCollection(node);\n                        }\n                    },\n\n                    cleanNode : function(node) {\n                        ko.dependencyDetection.ignore(function () {\n                            // First clean this node, where applicable\n                            if (cleanableNodeTypes[node.nodeType]) {\n                                cleanSingleNode(node);\n\n                                // ... then its descendants, where applicable\n                                if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                                    cleanNodesInList(node.getElementsByTagName(\"*\"));\n                                }\n                            }\n                        });\n\n                        return node;\n                    },\n\n                    removeNode : function(node) {\n                        ko.cleanNode(node);\n                        if (node.parentNode)\n                            node.parentNode.removeChild(node);\n                    },\n\n                    \"cleanExternalData\" : function (node) {\n                        // Special support for jQuery here because it's so commonly used.\n                        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData\n                        // so notify it to tear down any resources associated with the node & descendants here.\n                        if (jQueryInstance && (typeof jQueryInstance['cleanData'] == \"function\"))\n                            jQueryInstance['cleanData']([node]);\n                    }\n                };\n            })();\n            ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience\n            ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience\n            ko.exportSymbol('cleanNode', ko.cleanNode);\n            ko.exportSymbol('removeNode', ko.removeNode);\n            ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);\n            ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);\n            ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);\n            (function () {\n                var none = [0, \"\", \"\"],\n                    table = [1, \"<table>\", \"</table>\"],\n                    tbody = [2, \"<table><tbody>\", \"</tbody></table>\"],\n                    tr = [3, \"<table><tbody><tr>\", \"</tr></tbody></table>\"],\n                    select = [1, \"<select multiple='multiple'>\", \"</select>\"],\n                    lookup = {\n                        'thead': table,\n                        'tbody': table,\n                        'tfoot': table,\n                        'tr': tbody,\n                        'td': tr,\n                        'th': tr,\n                        'option': select,\n                        'optgroup': select\n                    },\n\n                    // This is needed for old IE if you're *not* using either jQuery or innerShiv. Doesn't affect other cases.\n                    mayRequireCreateElementHack = ko.utils.ieVersion <= 8;\n\n                function getWrap(tags) {\n                    var m = tags.match(/^(?:<!--.*?-->\\s*?)*?<([a-z]+)[\\s>]/);\n                    return (m && lookup[m[1]]) || none;\n                }\n\n                function simpleHtmlParse(html, documentContext) {\n                    documentContext || (documentContext = document);\n                    var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;\n\n                    // Based on jQuery's \"clean\" function, but only accounting for table-related elements.\n                    // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's \"clean\" function directly\n\n                    // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of\n                    // a descendant node. For example: \"<div><!-- mycomment -->abc</div>\" will get parsed as \"<div>abc</div>\"\n                    // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node\n                    // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.\n\n                    // Trim whitespace, otherwise indexOf won't work as expected\n                    var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement(\"div\"),\n                        wrap = getWrap(tags),\n                        depth = wrap[0];\n\n                    // Go to html and back, then peel off extra wrappers\n                    // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.\n                    var markup = \"ignored<div>\" + wrap[1] + html + wrap[2] + \"</div>\";\n                    if (typeof windowContext['innerShiv'] == \"function\") {\n                        // Note that innerShiv is deprecated in favour of html5shiv. We should consider adding\n                        // support for html5shiv (except if no explicit support is needed, e.g., if html5shiv\n                        // somehow shims the native APIs so it just works anyway)\n                        div.appendChild(windowContext['innerShiv'](markup));\n                    } else {\n                        if (mayRequireCreateElementHack) {\n                            // The document.createElement('my-element') trick to enable custom elements in IE6-8\n                            // only works if we assign innerHTML on an element associated with that document.\n                            documentContext.body.appendChild(div);\n                        }\n\n                        div.innerHTML = markup;\n\n                        if (mayRequireCreateElementHack) {\n                            div.parentNode.removeChild(div);\n                        }\n                    }\n\n                    // Move to the right depth\n                    while (depth--)\n                        div = div.lastChild;\n\n                    return ko.utils.makeArray(div.lastChild.childNodes);\n                }\n\n                function jQueryHtmlParse(html, documentContext) {\n                    // jQuery's \"parseHTML\" function was introduced in jQuery 1.8.0 and is a documented public API.\n                    if (jQueryInstance['parseHTML']) {\n                        return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null\n                    } else {\n                        // For jQuery < 1.8.0, we fall back on the undocumented internal \"clean\" function.\n                        var elems = jQueryInstance['clean']([html], documentContext);\n\n                        // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.\n                        // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.\n                        // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.\n                        if (elems && elems[0]) {\n                            // Find the top-most parent element that's a direct child of a document fragment\n                            var elem = elems[0];\n                            while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)\n                                elem = elem.parentNode;\n                            // ... then detach it\n                            if (elem.parentNode)\n                                elem.parentNode.removeChild(elem);\n                        }\n\n                        return elems;\n                    }\n                }\n\n                ko.utils.parseHtmlFragment = function(html, documentContext) {\n                    return jQueryInstance ?\n                        jQueryHtmlParse(html, documentContext) :   // As below, benefit from jQuery's optimisations where possible\n                        simpleHtmlParse(html, documentContext);  // ... otherwise, this simple logic will do in most common cases.\n                };\n\n                ko.utils.parseHtmlForTemplateNodes = function(html, documentContext) {\n                    var nodes = ko.utils.parseHtmlFragment(html, documentContext);\n                    return (nodes.length && nodes[0].parentElement) || ko.utils.moveCleanedNodesToContainerElement(nodes);\n                };\n\n                ko.utils.setHtml = function(node, html) {\n                    ko.utils.emptyDomNode(node);\n\n                    // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it\n                    html = ko.utils.unwrapObservable(html);\n\n                    if ((html !== null) && (html !== undefined)) {\n                        if (typeof html != 'string')\n                            html = html.toString();\n\n                        // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,\n                        // for example <tr> elements which are not normally allowed to exist on their own.\n                        // If you've referenced jQuery we'll use that rather than duplicating its code.\n                        if (jQueryInstance) {\n                            jQueryInstance(node)['html'](html);\n                        } else {\n                            // ... otherwise, use KO's own parsing logic.\n                            var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);\n                            for (var i = 0; i < parsedNodes.length; i++)\n                                node.appendChild(parsedNodes[i]);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);\n            ko.exportSymbol('utils.setHtml', ko.utils.setHtml);\n\n            ko.memoization = (function () {\n                var memos = {};\n\n                function randomMax8HexChars() {\n                    return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);\n                }\n                function generateRandomId() {\n                    return randomMax8HexChars() + randomMax8HexChars();\n                }\n                function findMemoNodes(rootNode, appendToArray) {\n                    if (!rootNode)\n                        return;\n                    if (rootNode.nodeType == 8) {\n                        var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);\n                        if (memoId != null)\n                            appendToArray.push({ domNode: rootNode, memoId: memoId });\n                    } else if (rootNode.nodeType == 1) {\n                        for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)\n                            findMemoNodes(childNodes[i], appendToArray);\n                    }\n                }\n\n                return {\n                    memoize: function (callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"You can only pass a function to ko.memoization.memoize()\");\n                        var memoId = generateRandomId();\n                        memos[memoId] = callback;\n                        return \"<!--[ko_memo:\" + memoId + \"]-->\";\n                    },\n\n                    unmemoize: function (memoId, callbackParams) {\n                        var callback = memos[memoId];\n                        if (callback === undefined)\n                            throw new Error(\"Couldn't find any memo with ID \" + memoId + \". Perhaps it's already been unmemoized.\");\n                        try {\n                            callback.apply(null, callbackParams || []);\n                            return true;\n                        }\n                        finally { delete memos[memoId]; }\n                    },\n\n                    unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {\n                        var memos = [];\n                        findMemoNodes(domNode, memos);\n                        for (var i = 0, j = memos.length; i < j; i++) {\n                            var node = memos[i].domNode;\n                            var combinedParams = [node];\n                            if (extraCallbackParamsArray)\n                                ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);\n                            ko.memoization.unmemoize(memos[i].memoId, combinedParams);\n                            node.nodeValue = \"\"; // Neuter this node so we don't try to unmemoize it again\n                            if (node.parentNode)\n                                node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)\n                        }\n                    },\n\n                    parseMemoText: function (memoText) {\n                        var match = memoText.match(/^\\[ko_memo\\:(.*?)\\]$/);\n                        return match ? match[1] : null;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('memoization', ko.memoization);\n            ko.exportSymbol('memoization.memoize', ko.memoization.memoize);\n            ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);\n            ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);\n            ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);\n            ko.tasks = (function () {\n                var scheduler,\n                    taskQueue = [],\n                    taskQueueLength = 0,\n                    nextHandle = 1,\n                    nextIndexToProcess = 0;\n\n                if (window['MutationObserver']) {\n                    // Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+\n                    // From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT\n                    scheduler = (function (callback) {\n                        var div = document.createElement(\"div\");\n                        new MutationObserver(callback).observe(div, {attributes: true});\n                        return function () { div.classList.toggle(\"foo\"); };\n                    })(scheduledProcess);\n                } else if (document && \"onreadystatechange\" in document.createElement(\"script\")) {\n                    // IE 6-10\n                    // From https://github.com/YuzuJS/setImmediate * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola * License: MIT\n                    scheduler = function (callback) {\n                        var script = document.createElement(\"script\");\n                        script.onreadystatechange = function () {\n                            script.onreadystatechange = null;\n                            document.documentElement.removeChild(script);\n                            script = null;\n                            callback();\n                        };\n                        document.documentElement.appendChild(script);\n                    };\n                } else {\n                    scheduler = function (callback) {\n                        setTimeout(callback, 0);\n                    };\n                }\n\n                function processTasks() {\n                    if (taskQueueLength) {\n                        // Each mark represents the end of a logical group of tasks and the number of these groups is\n                        // limited to prevent unchecked recursion.\n                        var mark = taskQueueLength, countMarks = 0;\n\n                        // nextIndexToProcess keeps track of where we are in the queue; processTasks can be called recursively without issue\n                        for (var task; nextIndexToProcess < taskQueueLength; ) {\n                            if (task = taskQueue[nextIndexToProcess++]) {\n                                if (nextIndexToProcess > mark) {\n                                    if (++countMarks >= 5000) {\n                                        nextIndexToProcess = taskQueueLength;   // skip all tasks remaining in the queue since any of them could be causing the recursion\n                                        ko.utils.deferError(Error(\"'Too much recursion' after processing \" + countMarks + \" task groups.\"));\n                                        break;\n                                    }\n                                    mark = taskQueueLength;\n                                }\n                                try {\n                                    task();\n                                } catch (ex) {\n                                    ko.utils.deferError(ex);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                function scheduledProcess() {\n                    processTasks();\n\n                    // Reset the queue\n                    nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                }\n\n                function scheduleTaskProcessing() {\n                    ko.tasks['scheduler'](scheduledProcess);\n                }\n\n                var tasks = {\n                    'scheduler': scheduler,     // Allow overriding the scheduler\n\n                    schedule: function (func) {\n                        if (!taskQueueLength) {\n                            scheduleTaskProcessing();\n                        }\n\n                        taskQueue[taskQueueLength++] = func;\n                        return nextHandle++;\n                    },\n\n                    cancel: function (handle) {\n                        var index = handle - (nextHandle - taskQueueLength);\n                        if (index >= nextIndexToProcess && index < taskQueueLength) {\n                            taskQueue[index] = null;\n                        }\n                    },\n\n                    // For testing only: reset the queue and return the previous queue length\n                    'resetForTesting': function () {\n                        var length = taskQueueLength - nextIndexToProcess;\n                        nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                        return length;\n                    },\n\n                    runEarly: processTasks\n                };\n\n                return tasks;\n            })();\n\n            ko.exportSymbol('tasks', ko.tasks);\n            ko.exportSymbol('tasks.schedule', ko.tasks.schedule);\n//ko.exportSymbol('tasks.cancel', ko.tasks.cancel);  \"cancel\" isn't minified\n            ko.exportSymbol('tasks.runEarly', ko.tasks.runEarly);\n            ko.extenders = {\n                'throttle': function(target, timeout) {\n                    // Throttling means two things:\n\n                    // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies\n                    //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate\n                    target['throttleEvaluation'] = timeout;\n\n                    // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*\n                    //     so the target cannot change value synchronously or faster than a certain rate\n                    var writeTimeoutInstance = null;\n                    return ko.dependentObservable({\n                        'read': target,\n                        'write': function(value) {\n                            clearTimeout(writeTimeoutInstance);\n                            writeTimeoutInstance = ko.utils.setTimeout(function() {\n                                target(value);\n                            }, timeout);\n                        }\n                    });\n                },\n\n                'rateLimit': function(target, options) {\n                    var timeout, method, limitFunction;\n\n                    if (typeof options == 'number') {\n                        timeout = options;\n                    } else {\n                        timeout = options['timeout'];\n                        method = options['method'];\n                    }\n\n                    // rateLimit supersedes deferred updates\n                    target._deferUpdates = false;\n\n                    limitFunction = typeof method == 'function' ? method : method == 'notifyWhenChangesStop' ?  debounce : throttle;\n                    target.limit(function(callback) {\n                        return limitFunction(callback, timeout, options);\n                    });\n                },\n\n                'deferred': function(target, options) {\n                    if (options !== true) {\n                        throw new Error('The \\'deferred\\' extender only accepts the value \\'true\\', because it is not supported to turn deferral off once enabled.')\n                    }\n\n                    if (!target._deferUpdates) {\n                        target._deferUpdates = true;\n                        target.limit(function (callback) {\n                            var handle,\n                                ignoreUpdates = false;\n                            return function () {\n                                if (!ignoreUpdates) {\n                                    ko.tasks.cancel(handle);\n                                    handle = ko.tasks.schedule(callback);\n\n                                    try {\n                                        ignoreUpdates = true;\n                                        target['notifySubscribers'](undefined, 'dirty');\n                                    } finally {\n                                        ignoreUpdates = false;\n                                    }\n                                }\n                            };\n                        });\n                    }\n                },\n\n                'notify': function(target, notifyWhen) {\n                    target[\"equalityComparer\"] = notifyWhen == \"always\" ?\n                        null :  // null equalityComparer means to always notify\n                        valuesArePrimitiveAndEqual;\n                }\n            };\n\n            var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };\n            function valuesArePrimitiveAndEqual(a, b) {\n                var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);\n                return oldValueIsPrimitive ? (a === b) : false;\n            }\n\n            function throttle(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    if (!timeoutInstance) {\n                        timeoutInstance = ko.utils.setTimeout(function () {\n                            timeoutInstance = undefined;\n                            callback();\n                        }, timeout);\n                    }\n                };\n            }\n\n            function debounce(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    clearTimeout(timeoutInstance);\n                    timeoutInstance = ko.utils.setTimeout(callback, timeout);\n                };\n            }\n\n            function applyExtenders(requestedExtenders) {\n                var target = this;\n                if (requestedExtenders) {\n                    ko.utils.objectForEach(requestedExtenders, function(key, value) {\n                        var extenderHandler = ko.extenders[key];\n                        if (typeof extenderHandler == 'function') {\n                            target = extenderHandler(target, value) || target;\n                        }\n                    });\n                }\n                return target;\n            }\n\n            ko.exportSymbol('extenders', ko.extenders);\n\n            ko.subscription = function (target, callback, disposeCallback) {\n                this._target = target;\n                this._callback = callback;\n                this._disposeCallback = disposeCallback;\n                this._isDisposed = false;\n                this._node = null;\n                this._domNodeDisposalCallback = null;\n                ko.exportProperty(this, 'dispose', this.dispose);\n                ko.exportProperty(this, 'disposeWhenNodeIsRemoved', this.disposeWhenNodeIsRemoved);\n            };\n            ko.subscription.prototype.dispose = function () {\n                var self = this;\n                if (!self._isDisposed) {\n                    if (self._domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(self._node, self._domNodeDisposalCallback);\n                    }\n                    self._isDisposed = true;\n                    self._disposeCallback();\n\n                    self._target = self._callback = self._disposeCallback = self._node = self._domNodeDisposalCallback = null;\n                }\n            };\n            ko.subscription.prototype.disposeWhenNodeIsRemoved = function (node) {\n                this._node = node;\n                ko.utils.domNodeDisposal.addDisposeCallback(node, this._domNodeDisposalCallback = this.dispose.bind(this));\n            };\n\n            ko.subscribable = function () {\n                ko.utils.setPrototypeOfOrExtend(this, ko_subscribable_fn);\n                ko_subscribable_fn.init(this);\n            }\n\n            var defaultEvent = \"change\";\n\n// Moved out of \"limit\" to avoid the extra closure\n            function limitNotifySubscribers(value, event) {\n                if (!event || event === defaultEvent) {\n                    this._limitChange(value);\n                } else if (event === 'beforeChange') {\n                    this._limitBeforeChange(value);\n                } else {\n                    this._origNotifySubscribers(value, event);\n                }\n            }\n\n            var ko_subscribable_fn = {\n                init: function(instance) {\n                    instance._subscriptions = { \"change\": [] };\n                    instance._versionNumber = 1;\n                },\n\n                subscribe: function (callback, callbackTarget, event) {\n                    var self = this;\n\n                    event = event || defaultEvent;\n                    var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;\n\n                    var subscription = new ko.subscription(self, boundCallback, function () {\n                        ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);\n                        if (self.afterSubscriptionRemove)\n                            self.afterSubscriptionRemove(event);\n                    });\n\n                    if (self.beforeSubscriptionAdd)\n                        self.beforeSubscriptionAdd(event);\n\n                    if (!self._subscriptions[event])\n                        self._subscriptions[event] = [];\n                    self._subscriptions[event].push(subscription);\n\n                    return subscription;\n                },\n\n                \"notifySubscribers\": function (valueToNotify, event) {\n                    event = event || defaultEvent;\n                    if (event === defaultEvent) {\n                        this.updateVersion();\n                    }\n                    if (this.hasSubscriptionsForEvent(event)) {\n                        var subs = event === defaultEvent && this._changeSubscriptions || this._subscriptions[event].slice(0);\n                        try {\n                            ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)\n                            for (var i = 0, subscription; subscription = subs[i]; ++i) {\n                                // In case a subscription was disposed during the arrayForEach cycle, check\n                                // for isDisposed on each subscription before invoking its callback\n                                if (!subscription._isDisposed)\n                                    subscription._callback(valueToNotify);\n                            }\n                        } finally {\n                            ko.dependencyDetection.end(); // End suppressing dependency detection\n                        }\n                    }\n                },\n\n                getVersion: function () {\n                    return this._versionNumber;\n                },\n\n                hasChanged: function (versionToCheck) {\n                    return this.getVersion() !== versionToCheck;\n                },\n\n                updateVersion: function () {\n                    ++this._versionNumber;\n                },\n\n                limit: function(limitFunction) {\n                    var self = this, selfIsObservable = ko.isObservable(self),\n                        ignoreBeforeChange, notifyNextChange, previousValue, pendingValue, didUpdate,\n                        beforeChange = 'beforeChange';\n\n                    if (!self._origNotifySubscribers) {\n                        self._origNotifySubscribers = self[\"notifySubscribers\"];\n                        self[\"notifySubscribers\"] = limitNotifySubscribers;\n                    }\n\n                    var finish = limitFunction(function() {\n                        self._notificationIsPending = false;\n\n                        // If an observable provided a reference to itself, access it to get the latest value.\n                        // This allows computed observables to delay calculating their value until needed.\n                        if (selfIsObservable && pendingValue === self) {\n                            pendingValue = self._evalIfChanged ? self._evalIfChanged() : self();\n                        }\n                        var shouldNotify = notifyNextChange || (didUpdate && self.isDifferent(previousValue, pendingValue));\n\n                        didUpdate = notifyNextChange = ignoreBeforeChange = false;\n\n                        if (shouldNotify) {\n                            self._origNotifySubscribers(previousValue = pendingValue);\n                        }\n                    });\n\n                    self._limitChange = function(value, isDirty) {\n                        if (!isDirty || !self._notificationIsPending) {\n                            didUpdate = !isDirty;\n                        }\n                        self._changeSubscriptions = self._subscriptions[defaultEvent].slice(0);\n                        self._notificationIsPending = ignoreBeforeChange = true;\n                        pendingValue = value;\n                        finish();\n                    };\n                    self._limitBeforeChange = function(value) {\n                        if (!ignoreBeforeChange) {\n                            previousValue = value;\n                            self._origNotifySubscribers(value, beforeChange);\n                        }\n                    };\n                    self._recordUpdate = function() {\n                        didUpdate = true;\n                    };\n                    self._notifyNextChangeIfValueIsDifferent = function() {\n                        if (self.isDifferent(previousValue, self.peek(true /*evaluate*/))) {\n                            notifyNextChange = true;\n                        }\n                    };\n                },\n\n                hasSubscriptionsForEvent: function(event) {\n                    return this._subscriptions[event] && this._subscriptions[event].length;\n                },\n\n                getSubscriptionsCount: function (event) {\n                    if (event) {\n                        return this._subscriptions[event] && this._subscriptions[event].length || 0;\n                    } else {\n                        var total = 0;\n                        ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {\n                            if (eventName !== 'dirty')\n                                total += subscriptions.length;\n                        });\n                        return total;\n                    }\n                },\n\n                isDifferent: function(oldValue, newValue) {\n                    return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);\n                },\n\n                toString: function() {\n                    return '[object Object]'\n                },\n\n                extend: applyExtenders\n            };\n\n            ko.exportProperty(ko_subscribable_fn, 'init', ko_subscribable_fn.init);\n            ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);\n            ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);\n            ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);\n\n// For browsers that support proto assignment, we overwrite the prototype of each\n// observable instance. Since observables are functions, we need Function.prototype\n// to still be in the prototype chain.\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);\n            }\n\n            ko.subscribable['fn'] = ko_subscribable_fn;\n\n\n            ko.isSubscribable = function (instance) {\n                return instance != null && typeof instance.subscribe == \"function\" && typeof instance[\"notifySubscribers\"] == \"function\";\n            };\n\n            ko.exportSymbol('subscribable', ko.subscribable);\n            ko.exportSymbol('isSubscribable', ko.isSubscribable);\n\n            ko.computedContext = ko.dependencyDetection = (function () {\n                var outerFrames = [],\n                    currentFrame,\n                    lastId = 0;\n\n                // Return a unique ID that can be assigned to an observable for dependency tracking.\n                // Theoretically, you could eventually overflow the number storage size, resulting\n                // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53\n                // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would\n                // take over 285 years to reach that number.\n                // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html\n                function getId() {\n                    return ++lastId;\n                }\n\n                function begin(options) {\n                    outerFrames.push(currentFrame);\n                    currentFrame = options;\n                }\n\n                function end() {\n                    currentFrame = outerFrames.pop();\n                }\n\n                return {\n                    begin: begin,\n\n                    end: end,\n\n                    registerDependency: function (subscribable) {\n                        if (currentFrame) {\n                            if (!ko.isSubscribable(subscribable))\n                                throw new Error(\"Only subscribable things can act as dependencies\");\n                            currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));\n                        }\n                    },\n\n                    ignore: function (callback, callbackTarget, callbackArgs) {\n                        try {\n                            begin();\n                            return callback.apply(callbackTarget, callbackArgs || []);\n                        } finally {\n                            end();\n                        }\n                    },\n\n                    getDependenciesCount: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependenciesCount();\n                    },\n\n                    getDependencies: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependencies();\n                    },\n\n                    isInitial: function() {\n                        if (currentFrame)\n                            return currentFrame.isInitial;\n                    },\n\n                    computed: function() {\n                        if (currentFrame)\n                            return currentFrame.computed;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('computedContext', ko.computedContext);\n            ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);\n            ko.exportSymbol('computedContext.getDependencies', ko.computedContext.getDependencies);\n            ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);\n            ko.exportSymbol('computedContext.registerDependency', ko.computedContext.registerDependency);\n\n            ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);\n            var observableLatestValue = ko.utils.createSymbolOrString('_latestValue');\n\n            ko.observable = function (initialValue) {\n                function observable() {\n                    if (arguments.length > 0) {\n                        // Write\n\n                        // Ignore writes if the value hasn't changed\n                        if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {\n                            observable.valueWillMutate();\n                            observable[observableLatestValue] = arguments[0];\n                            observable.valueHasMutated();\n                        }\n                        return this; // Permits chained assignments\n                    }\n                    else {\n                        // Read\n                        ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a \"read\" operation\n                        return observable[observableLatestValue];\n                    }\n                }\n\n                observable[observableLatestValue] = initialValue;\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(observable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(observable);\n\n                // Inherit from 'observable'\n                ko.utils.setPrototypeOfOrExtend(observable, observableFn);\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](observable, true);\n                }\n\n                return observable;\n            }\n\n// Define prototype for observables\n            var observableFn = {\n                'equalityComparer': valuesArePrimitiveAndEqual,\n                peek: function() { return this[observableLatestValue]; },\n                valueHasMutated: function () {\n                    this['notifySubscribers'](this[observableLatestValue], 'spectate');\n                    this['notifySubscribers'](this[observableLatestValue]);\n                },\n                valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observable constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(observableFn, ko.subscribable['fn']);\n            }\n\n            var protoProperty = ko.observable.protoProperty = '__ko_proto__';\n            observableFn[protoProperty] = ko.observable;\n\n            ko.isObservable = function (instance) {\n                var proto = typeof instance == 'function' && instance[protoProperty];\n                if (proto && proto !== observableFn[protoProperty] && proto !== ko.computed['fn'][protoProperty]) {\n                    throw Error(\"Invalid object that looks like an observable; possibly from another Knockout instance\");\n                }\n                return !!proto;\n            };\n\n            ko.isWriteableObservable = function (instance) {\n                return (typeof instance == 'function' && (\n                    (instance[protoProperty] === observableFn[protoProperty]) ||  // Observable\n                    (instance[protoProperty] === ko.computed['fn'][protoProperty] && instance.hasWriteFunction)));   // Writable computed observable\n            };\n\n            ko.exportSymbol('observable', ko.observable);\n            ko.exportSymbol('isObservable', ko.isObservable);\n            ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('observable.fn', observableFn);\n            ko.exportProperty(observableFn, 'peek', observableFn.peek);\n            ko.exportProperty(observableFn, 'valueHasMutated', observableFn.valueHasMutated);\n            ko.exportProperty(observableFn, 'valueWillMutate', observableFn.valueWillMutate);\n            ko.observableArray = function (initialValues) {\n                initialValues = initialValues || [];\n\n                if (typeof initialValues != 'object' || !('length' in initialValues))\n                    throw new Error(\"The argument passed when initializing an observable array must be an array, or null, or undefined.\");\n\n                var result = ko.observable(initialValues);\n                ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);\n                return result.extend({'trackArrayChanges':true});\n            };\n\n            ko.observableArray['fn'] = {\n                'remove': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var removedValues = [];\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    for (var i = 0; i < underlyingArray.length; i++) {\n                        var value = underlyingArray[i];\n                        if (predicate(value)) {\n                            if (removedValues.length === 0) {\n                                this.valueWillMutate();\n                            }\n                            if (underlyingArray[i] !== value) {\n                                throw Error(\"Array modified during remove; cannot remove item\");\n                            }\n                            removedValues.push(value);\n                            underlyingArray.splice(i, 1);\n                            i--;\n                        }\n                    }\n                    if (removedValues.length) {\n                        this.valueHasMutated();\n                    }\n                    return removedValues;\n                },\n\n                'removeAll': function (arrayOfValues) {\n                    // If you passed zero args, we remove everything\n                    if (arrayOfValues === undefined) {\n                        var underlyingArray = this.peek();\n                        var allValues = underlyingArray.slice(0);\n                        this.valueWillMutate();\n                        underlyingArray.splice(0, underlyingArray.length);\n                        this.valueHasMutated();\n                        return allValues;\n                    }\n                    // If you passed an arg, we interpret it as an array of entries to remove\n                    if (!arrayOfValues)\n                        return [];\n                    return this['remove'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'destroy': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    this.valueWillMutate();\n                    for (var i = underlyingArray.length - 1; i >= 0; i--) {\n                        var value = underlyingArray[i];\n                        if (predicate(value))\n                            value[\"_destroy\"] = true;\n                    }\n                    this.valueHasMutated();\n                },\n\n                'destroyAll': function (arrayOfValues) {\n                    // If you passed zero args, we destroy everything\n                    if (arrayOfValues === undefined)\n                        return this['destroy'](function() { return true });\n\n                    // If you passed an arg, we interpret it as an array of entries to destroy\n                    if (!arrayOfValues)\n                        return [];\n                    return this['destroy'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'indexOf': function (item) {\n                    var underlyingArray = this();\n                    return ko.utils.arrayIndexOf(underlyingArray, item);\n                },\n\n                'replace': function(oldItem, newItem) {\n                    var index = this['indexOf'](oldItem);\n                    if (index >= 0) {\n                        this.valueWillMutate();\n                        this.peek()[index] = newItem;\n                        this.valueHasMutated();\n                    }\n                },\n\n                'sorted': function (compareFunction) {\n                    var arrayCopy = this().slice(0);\n                    return compareFunction ? arrayCopy.sort(compareFunction) : arrayCopy.sort();\n                },\n\n                'reversed': function () {\n                    return this().slice(0).reverse();\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observableArray constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);\n            }\n\n// Populate ko.observableArray.fn with read/write functions from native arrays\n// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array\n// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale\n            ko.utils.arrayForEach([\"pop\", \"push\", \"reverse\", \"shift\", \"sort\", \"splice\", \"unshift\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    // Use \"peek\" to avoid creating a subscription in any computed that we're executing in the context of\n                    // (for consistency with mutating regular observables)\n                    var underlyingArray = this.peek();\n                    this.valueWillMutate();\n                    this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);\n                    var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);\n                    this.valueHasMutated();\n                    // The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.\n                    return methodCallResult === underlyingArray ? this : methodCallResult;\n                };\n            });\n\n// Populate ko.observableArray.fn with read-only functions from native arrays\n            ko.utils.arrayForEach([\"slice\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    var underlyingArray = this();\n                    return underlyingArray[methodName].apply(underlyingArray, arguments);\n                };\n            });\n\n            ko.isObservableArray = function (instance) {\n                return ko.isObservable(instance)\n                    && typeof instance[\"remove\"] == \"function\"\n                    && typeof instance[\"push\"] == \"function\";\n            };\n\n            ko.exportSymbol('observableArray', ko.observableArray);\n            ko.exportSymbol('isObservableArray', ko.isObservableArray);\n            var arrayChangeEventName = 'arrayChange';\n            ko.extenders['trackArrayChanges'] = function(target, options) {\n                // Use the provided options--each call to trackArrayChanges overwrites the previously set options\n                target.compareArrayOptions = {};\n                if (options && typeof options == \"object\") {\n                    ko.utils.extend(target.compareArrayOptions, options);\n                }\n                target.compareArrayOptions['sparse'] = true;\n\n                // Only modify the target observable once\n                if (target.cacheDiffForKnownOperation) {\n                    return;\n                }\n                var trackingChanges = false,\n                    cachedDiff = null,\n                    changeSubscription,\n                    spectateSubscription,\n                    pendingChanges = 0,\n                    previousContents,\n                    underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,\n                    underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;\n\n                // Watch \"subscribe\" calls, and for array change events, ensure change tracking is enabled\n                target.beforeSubscriptionAdd = function (event) {\n                    if (underlyingBeforeSubscriptionAddFunction) {\n                        underlyingBeforeSubscriptionAddFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName) {\n                        trackChanges();\n                    }\n                };\n                // Watch \"dispose\" calls, and for array change events, ensure change tracking is disabled when all are disposed\n                target.afterSubscriptionRemove = function (event) {\n                    if (underlyingAfterSubscriptionRemoveFunction) {\n                        underlyingAfterSubscriptionRemoveFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                        if (changeSubscription) {\n                            changeSubscription.dispose();\n                        }\n                        if (spectateSubscription) {\n                            spectateSubscription.dispose();\n                        }\n                        spectateSubscription = changeSubscription = null;\n                        trackingChanges = false;\n                        previousContents = undefined;\n                    }\n                };\n\n                function trackChanges() {\n                    if (trackingChanges) {\n                        // Whenever there's a new subscription and there are pending notifications, make sure all previous\n                        // subscriptions are notified of the change so that all subscriptions are in sync.\n                        notifyChanges();\n                        return;\n                    }\n\n                    trackingChanges = true;\n\n                    // Track how many times the array actually changed value\n                    spectateSubscription = target.subscribe(function () {\n                        ++pendingChanges;\n                    }, null, \"spectate\");\n\n                    // Each time the array changes value, capture a clone so that on the next\n                    // change it's possible to produce a diff\n                    previousContents = [].concat(target.peek() || []);\n                    cachedDiff = null;\n                    changeSubscription = target.subscribe(notifyChanges);\n\n                    function notifyChanges() {\n                        if (pendingChanges) {\n                            // Make a copy of the current contents and ensure it's an array\n                            var currentContents = [].concat(target.peek() || []), changes;\n\n                            // Compute the diff and issue notifications, but only if someone is listening\n                            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                                changes = getChanges(previousContents, currentContents);\n                            }\n\n                            // Eliminate references to the old, removed items, so they can be GCed\n                            previousContents = currentContents;\n                            cachedDiff = null;\n                            pendingChanges = 0;\n\n                            if (changes && changes.length) {\n                                target['notifySubscribers'](changes, arrayChangeEventName);\n                            }\n                        }\n                    }\n                }\n\n                function getChanges(previousContents, currentContents) {\n                    // We try to re-use cached diffs.\n                    // The scenarios where pendingChanges > 1 are when using rate limiting or deferred updates,\n                    // which without this check would not be compatible with arrayChange notifications. Normally,\n                    // notifications are issued immediately so we wouldn't be queueing up more than one.\n                    if (!cachedDiff || pendingChanges > 1) {\n                        cachedDiff = ko.utils.compareArrays(previousContents, currentContents, target.compareArrayOptions);\n                    }\n\n                    return cachedDiff;\n                }\n\n                target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {\n                    // Only run if we're currently tracking changes for this observable array\n                    // and there aren't any pending deferred notifications.\n                    if (!trackingChanges || pendingChanges) {\n                        return;\n                    }\n                    var diff = [],\n                        arrayLength = rawArray.length,\n                        argsLength = args.length,\n                        offset = 0;\n\n                    function pushDiff(status, value, index) {\n                        return diff[diff.length] = { 'status': status, 'value': value, 'index': index };\n                    }\n                    switch (operationName) {\n                        case 'push':\n                            offset = arrayLength;\n                        case 'unshift':\n                            for (var index = 0; index < argsLength; index++) {\n                                pushDiff('added', args[index], offset + index);\n                            }\n                            break;\n\n                        case 'pop':\n                            offset = arrayLength - 1;\n                        case 'shift':\n                            if (arrayLength) {\n                                pushDiff('deleted', rawArray[offset], offset);\n                            }\n                            break;\n\n                        case 'splice':\n                            // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].\n                            // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice\n                            var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),\n                                endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),\n                                endAddIndex = startIndex + argsLength - 2,\n                                endIndex = Math.max(endDeleteIndex, endAddIndex),\n                                additions = [], deletions = [];\n                            for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {\n                                if (index < endDeleteIndex)\n                                    deletions.push(pushDiff('deleted', rawArray[index], index));\n                                if (index < endAddIndex)\n                                    additions.push(pushDiff('added', args[argsIndex], index));\n                            }\n                            ko.utils.findMovesInArrayComparison(deletions, additions);\n                            break;\n\n                        default:\n                            return;\n                    }\n                    cachedDiff = diff;\n                };\n            };\n            var computedState = ko.utils.createSymbolOrString('_state');\n\n            ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {\n                if (typeof evaluatorFunctionOrOptions === \"object\") {\n                    // Single-parameter syntax - everything is on this \"options\" param\n                    options = evaluatorFunctionOrOptions;\n                } else {\n                    // Multi-parameter syntax - construct the options according to the params passed\n                    options = options || {};\n                    if (evaluatorFunctionOrOptions) {\n                        options[\"read\"] = evaluatorFunctionOrOptions;\n                    }\n                }\n                if (typeof options[\"read\"] != \"function\")\n                    throw Error(\"Pass a function that returns the value of the ko.computed\");\n\n                var writeFunction = options[\"write\"];\n                var state = {\n                    latestValue: undefined,\n                    isStale: true,\n                    isDirty: true,\n                    isBeingEvaluated: false,\n                    suppressDisposalUntilDisposeWhenReturnsFalse: false,\n                    isDisposed: false,\n                    pure: false,\n                    isSleeping: false,\n                    readFunction: options[\"read\"],\n                    evaluatorFunctionTarget: evaluatorFunctionTarget || options[\"owner\"],\n                    disposeWhenNodeIsRemoved: options[\"disposeWhenNodeIsRemoved\"] || options.disposeWhenNodeIsRemoved || null,\n                    disposeWhen: options[\"disposeWhen\"] || options.disposeWhen,\n                    domNodeDisposalCallback: null,\n                    dependencyTracking: {},\n                    dependenciesCount: 0,\n                    evaluationTimeoutInstance: null\n                };\n\n                function computedObservable() {\n                    if (arguments.length > 0) {\n                        if (typeof writeFunction === \"function\") {\n                            // Writing a value\n                            writeFunction.apply(state.evaluatorFunctionTarget, arguments);\n                        } else {\n                            throw new Error(\"Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.\");\n                        }\n                        return this; // Permits chained assignments\n                    } else {\n                        // Reading the value\n                        if (!state.isDisposed) {\n                            ko.dependencyDetection.registerDependency(computedObservable);\n                        }\n                        if (state.isDirty || (state.isSleeping && computedObservable.haveDependenciesChanged())) {\n                            computedObservable.evaluateImmediate();\n                        }\n                        return state.latestValue;\n                    }\n                }\n\n                computedObservable[computedState] = state;\n                computedObservable.hasWriteFunction = typeof writeFunction === \"function\";\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(computedObservable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(computedObservable);\n\n                // Inherit from 'computed'\n                ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);\n\n                if (options['pure']) {\n                    state.pure = true;\n                    state.isSleeping = true;     // Starts off sleeping; will awake on the first subscription\n                    ko.utils.extend(computedObservable, pureComputedOverrides);\n                } else if (options['deferEvaluation']) {\n                    ko.utils.extend(computedObservable, deferEvaluationOverrides);\n                }\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](computedObservable, true);\n                }\n\n                if (DEBUG) {\n                    // #1731 - Aid debugging by exposing the computed's options\n                    computedObservable[\"_options\"] = options;\n                }\n\n                if (state.disposeWhenNodeIsRemoved) {\n                    // Since this computed is associated with a DOM node, and we don't want to dispose the computed\n                    // until the DOM node is *removed* from the document (as opposed to never having been in the document),\n                    // we'll prevent disposal until \"disposeWhen\" first returns false.\n                    state.suppressDisposalUntilDisposeWhenReturnsFalse = true;\n\n                    // disposeWhenNodeIsRemoved: true can be used to opt into the \"only dispose after first false result\"\n                    // behaviour even if there's no specific node to watch. In that case, clear the option so we don't try\n                    // to watch for a non-node's disposal. This technique is intended for KO's internal use only and shouldn't\n                    // be documented or used by application code, as it's likely to change in a future version of KO.\n                    if (!state.disposeWhenNodeIsRemoved.nodeType) {\n                        state.disposeWhenNodeIsRemoved = null;\n                    }\n                }\n\n                // Evaluate, unless sleeping or deferEvaluation is true\n                if (!state.isSleeping && !options['deferEvaluation']) {\n                    computedObservable.evaluateImmediate();\n                }\n\n                // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is\n                // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).\n                if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {\n                    ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {\n                        computedObservable.dispose();\n                    });\n                }\n\n                return computedObservable;\n            };\n\n// Utility function that disposes a given dependencyTracking entry\n            function computedDisposeDependencyCallback(id, entryToDispose) {\n                if (entryToDispose !== null && entryToDispose.dispose) {\n                    entryToDispose.dispose();\n                }\n            }\n\n// This function gets called each time a dependency is detected while evaluating a computed.\n// It's factored out as a shared function to avoid creating unnecessary function instances during evaluation.\n            function computedBeginDependencyDetectionCallback(subscribable, id) {\n                var computedObservable = this.computedObservable,\n                    state = computedObservable[computedState];\n                if (!state.isDisposed) {\n                    if (this.disposalCount && this.disposalCandidates[id]) {\n                        // Don't want to dispose this subscription, as it's still being used\n                        computedObservable.addDependencyTracking(id, subscribable, this.disposalCandidates[id]);\n                        this.disposalCandidates[id] = null; // No need to actually delete the property - disposalCandidates is a transient object anyway\n                        --this.disposalCount;\n                    } else if (!state.dependencyTracking[id]) {\n                        // Brand new subscription - add it\n                        computedObservable.addDependencyTracking(id, subscribable, state.isSleeping ? { _target: subscribable } : computedObservable.subscribeToDependency(subscribable));\n                    }\n                    // If the observable we've accessed has a pending notification, ensure we get notified of the actual final value (bypass equality checks)\n                    if (subscribable._notificationIsPending) {\n                        subscribable._notifyNextChangeIfValueIsDifferent();\n                    }\n                }\n            }\n\n            var computedFn = {\n                \"equalityComparer\": valuesArePrimitiveAndEqual,\n                getDependenciesCount: function () {\n                    return this[computedState].dependenciesCount;\n                },\n                getDependencies: function () {\n                    var dependencyTracking = this[computedState].dependencyTracking, dependentObservables = [];\n\n                    ko.utils.objectForEach(dependencyTracking, function (id, dependency) {\n                        dependentObservables[dependency._order] = dependency._target;\n                    });\n\n                    return dependentObservables;\n                },\n                hasAncestorDependency: function (obs) {\n                    if (!this[computedState].dependenciesCount) {\n                        return false;\n                    }\n                    var dependencies = this.getDependencies();\n                    if (ko.utils.arrayIndexOf(dependencies, obs) !== -1) {\n                        return true;\n                    }\n                    return !!ko.utils.arrayFirst(dependencies, function (dep) {\n                        return dep.hasAncestorDependency && dep.hasAncestorDependency(obs);\n                    });\n                },\n                addDependencyTracking: function (id, target, trackingObj) {\n                    if (this[computedState].pure && target === this) {\n                        throw Error(\"A 'pure' computed must not be called recursively\");\n                    }\n\n                    this[computedState].dependencyTracking[id] = trackingObj;\n                    trackingObj._order = this[computedState].dependenciesCount++;\n                    trackingObj._version = target.getVersion();\n                },\n                haveDependenciesChanged: function () {\n                    var id, dependency, dependencyTracking = this[computedState].dependencyTracking;\n                    for (id in dependencyTracking) {\n                        if (Object.prototype.hasOwnProperty.call(dependencyTracking, id)) {\n                            dependency = dependencyTracking[id];\n                            if ((this._evalDelayed && dependency._target._notificationIsPending) || dependency._target.hasChanged(dependency._version)) {\n                                return true;\n                            }\n                        }\n                    }\n                },\n                markDirty: function () {\n                    // Process \"dirty\" events if we can handle delayed notifications\n                    if (this._evalDelayed && !this[computedState].isBeingEvaluated) {\n                        this._evalDelayed(false /*isChange*/);\n                    }\n                },\n                isActive: function () {\n                    var state = this[computedState];\n                    return state.isDirty || state.dependenciesCount > 0;\n                },\n                respondToChange: function () {\n                    // Ignore \"change\" events if we've already scheduled a delayed notification\n                    if (!this._notificationIsPending) {\n                        this.evaluatePossiblyAsync();\n                    } else if (this[computedState].isDirty) {\n                        this[computedState].isStale = true;\n                    }\n                },\n                subscribeToDependency: function (target) {\n                    if (target._deferUpdates) {\n                        var dirtySub = target.subscribe(this.markDirty, this, 'dirty'),\n                            changeSub = target.subscribe(this.respondToChange, this);\n                        return {\n                            _target: target,\n                            dispose: function () {\n                                dirtySub.dispose();\n                                changeSub.dispose();\n                            }\n                        };\n                    } else {\n                        return target.subscribe(this.evaluatePossiblyAsync, this);\n                    }\n                },\n                evaluatePossiblyAsync: function () {\n                    var computedObservable = this,\n                        throttleEvaluationTimeout = computedObservable['throttleEvaluation'];\n                    if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {\n                        clearTimeout(this[computedState].evaluationTimeoutInstance);\n                        this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(function () {\n                            computedObservable.evaluateImmediate(true /*notifyChange*/);\n                        }, throttleEvaluationTimeout);\n                    } else if (computedObservable._evalDelayed) {\n                        computedObservable._evalDelayed(true /*isChange*/);\n                    } else {\n                        computedObservable.evaluateImmediate(true /*notifyChange*/);\n                    }\n                },\n                evaluateImmediate: function (notifyChange) {\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        disposeWhen = state.disposeWhen,\n                        changed = false;\n\n                    if (state.isBeingEvaluated) {\n                        // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.\n                        // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost\n                        // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing\n                        // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387\n                        return;\n                    }\n\n                    // Do not evaluate (and possibly capture new dependencies) if disposed\n                    if (state.isDisposed) {\n                        return;\n                    }\n\n                    if (state.disposeWhenNodeIsRemoved && !ko.utils.domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {\n                        // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse\n                        if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {\n                            computedObservable.dispose();\n                            return;\n                        }\n                    } else {\n                        // It just did return false, so we can stop suppressing now\n                        state.suppressDisposalUntilDisposeWhenReturnsFalse = false;\n                    }\n\n                    state.isBeingEvaluated = true;\n                    try {\n                        changed = this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);\n                    } finally {\n                        state.isBeingEvaluated = false;\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {\n                    // This function is really just part of the evaluateImmediate logic. You would never call it from anywhere else.\n                    // Factoring it out into a separate function means it can be independent of the try/catch block in evaluateImmediate,\n                    // which contributes to saving about 40% off the CPU overhead of computed evaluation (on V8 at least).\n\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        changed = false;\n\n                    // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).\n                    // Then, during evaluation, we cross off any that are in fact still being used.\n                    var isInitial = state.pure ? undefined : !state.dependenciesCount,   // If we're evaluating when there are no previous dependencies, it must be the first time\n                        dependencyDetectionContext = {\n                            computedObservable: computedObservable,\n                            disposalCandidates: state.dependencyTracking,\n                            disposalCount: state.dependenciesCount\n                        };\n\n                    ko.dependencyDetection.begin({\n                        callbackTarget: dependencyDetectionContext,\n                        callback: computedBeginDependencyDetectionCallback,\n                        computed: computedObservable,\n                        isInitial: isInitial\n                    });\n\n                    state.dependencyTracking = {};\n                    state.dependenciesCount = 0;\n\n                    var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);\n\n                    if (!state.dependenciesCount) {\n                        computedObservable.dispose();\n                        changed = true; // When evaluation causes a disposal, make sure all dependent computeds get notified so they'll see the new state\n                    } else {\n                        changed = computedObservable.isDifferent(state.latestValue, newValue);\n                    }\n\n                    if (changed) {\n                        if (!state.isSleeping) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"beforeChange\");\n                        } else {\n                            computedObservable.updateVersion();\n                        }\n\n                        state.latestValue = newValue;\n                        if (DEBUG) computedObservable._latestValue = newValue;\n\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"spectate\");\n\n                        if (!state.isSleeping && notifyChange) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue);\n                        }\n                        if (computedObservable._recordUpdate) {\n                            computedObservable._recordUpdate();\n                        }\n                    }\n\n                    if (isInitial) {\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {\n                    // This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.\n                    // You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection\n                    // can be independent of try/finally blocks, which contributes to saving about 40% off the CPU\n                    // overhead of computed evaluation (on V8 at least).\n\n                    try {\n                        var readFunction = state.readFunction;\n                        return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();\n                    } finally {\n                        ko.dependencyDetection.end();\n\n                        // For each subscription no longer being used, remove it from the active subscriptions list and dispose it\n                        if (dependencyDetectionContext.disposalCount && !state.isSleeping) {\n                            ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);\n                        }\n\n                        state.isStale = state.isDirty = false;\n                    }\n                },\n                peek: function (evaluate) {\n                    // By default, peek won't re-evaluate, except while the computed is sleeping or to get the initial value when \"deferEvaluation\" is set.\n                    // Pass in true to evaluate if needed.\n                    var state = this[computedState];\n                    if ((state.isDirty && (evaluate || !state.dependenciesCount)) || (state.isSleeping && this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return state.latestValue;\n                },\n                limit: function (limitFunction) {\n                    // Override the limit function with one that delays evaluation as well\n                    ko.subscribable['fn'].limit.call(this, limitFunction);\n                    this._evalIfChanged = function () {\n                        if (!this[computedState].isSleeping) {\n                            if (this[computedState].isStale) {\n                                this.evaluateImmediate();\n                            } else {\n                                this[computedState].isDirty = false;\n                            }\n                        }\n                        return this[computedState].latestValue;\n                    };\n                    this._evalDelayed = function (isChange) {\n                        this._limitBeforeChange(this[computedState].latestValue);\n\n                        // Mark as dirty\n                        this[computedState].isDirty = true;\n                        if (isChange) {\n                            this[computedState].isStale = true;\n                        }\n\n                        // Pass the observable to the \"limit\" code, which will evaluate it when\n                        // it's time to do the notification.\n                        this._limitChange(this, !isChange /* isDirty */);\n                    };\n                },\n                dispose: function () {\n                    var state = this[computedState];\n                    if (!state.isSleeping && state.dependencyTracking) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose)\n                                dependency.dispose();\n                        });\n                    }\n                    if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);\n                    }\n                    state.dependencyTracking = undefined;\n                    state.dependenciesCount = 0;\n                    state.isDisposed = true;\n                    state.isStale = false;\n                    state.isDirty = false;\n                    state.isSleeping = false;\n                    state.disposeWhenNodeIsRemoved = undefined;\n                    state.disposeWhen = undefined;\n                    state.readFunction = undefined;\n                    if (!this.hasWriteFunction) {\n                        state.evaluatorFunctionTarget = undefined;\n                    }\n                }\n            };\n\n            var pureComputedOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // If asleep, wake up the computed by subscribing to any dependencies.\n                    var computedObservable = this,\n                        state = computedObservable[computedState];\n                    if (!state.isDisposed && state.isSleeping && event == 'change') {\n                        state.isSleeping = false;\n                        if (state.isStale || computedObservable.haveDependenciesChanged()) {\n                            state.dependencyTracking = null;\n                            state.dependenciesCount = 0;\n                            if (computedObservable.evaluateImmediate()) {\n                                computedObservable.updateVersion();\n                            }\n                        } else {\n                            // First put the dependencies in order\n                            var dependenciesOrder = [];\n                            ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                                dependenciesOrder[dependency._order] = id;\n                            });\n                            // Next, subscribe to each one\n                            ko.utils.arrayForEach(dependenciesOrder, function (id, order) {\n                                var dependency = state.dependencyTracking[id],\n                                    subscription = computedObservable.subscribeToDependency(dependency._target);\n                                subscription._order = order;\n                                subscription._version = dependency._version;\n                                state.dependencyTracking[id] = subscription;\n                            });\n                            // Waking dependencies may have triggered effects\n                            if (computedObservable.haveDependenciesChanged()) {\n                                if (computedObservable.evaluateImmediate()) {\n                                    computedObservable.updateVersion();\n                                }\n                            }\n                        }\n\n                        if (!state.isDisposed) {     // test since evaluating could trigger disposal\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                        }\n                    }\n                },\n                afterSubscriptionRemove: function (event) {\n                    var state = this[computedState];\n                    if (!state.isDisposed && event == 'change' && !this.hasSubscriptionsForEvent('change')) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose) {\n                                state.dependencyTracking[id] = {\n                                    _target: dependency._target,\n                                    _order: dependency._order,\n                                    _version: dependency._version\n                                };\n                                dependency.dispose();\n                            }\n                        });\n                        state.isSleeping = true;\n                        this[\"notifySubscribers\"](undefined, \"asleep\");\n                    }\n                },\n                getVersion: function () {\n                    // Because a pure computed is not automatically updated while it is sleeping, we can't\n                    // simply return the version number. Instead, we check if any of the dependencies have\n                    // changed and conditionally re-evaluate the computed observable.\n                    var state = this[computedState];\n                    if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return ko.subscribable['fn'].getVersion.call(this);\n                }\n            };\n\n            var deferEvaluationOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // This will force a computed with deferEvaluation to evaluate when the first subscription is registered.\n                    if (event == 'change' || event == 'beforeChange') {\n                        this.peek();\n                    }\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.computed constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(computedFn, ko.subscribable['fn']);\n            }\n\n// Set the proto values for ko.computed\n            var protoProp = ko.observable.protoProperty; // == \"__ko_proto__\"\n            computedFn[protoProp] = ko.computed;\n\n            ko.isComputed = function (instance) {\n                return (typeof instance == 'function' && instance[protoProp] === computedFn[protoProp]);\n            };\n\n            ko.isPureComputed = function (instance) {\n                return ko.isComputed(instance) && instance[computedState] && instance[computedState].pure;\n            };\n\n            ko.exportSymbol('computed', ko.computed);\n            ko.exportSymbol('dependentObservable', ko.computed);    // export ko.dependentObservable for backwards compatibility (1.x)\n            ko.exportSymbol('isComputed', ko.isComputed);\n            ko.exportSymbol('isPureComputed', ko.isPureComputed);\n            ko.exportSymbol('computed.fn', computedFn);\n            ko.exportProperty(computedFn, 'peek', computedFn.peek);\n            ko.exportProperty(computedFn, 'dispose', computedFn.dispose);\n            ko.exportProperty(computedFn, 'isActive', computedFn.isActive);\n            ko.exportProperty(computedFn, 'getDependenciesCount', computedFn.getDependenciesCount);\n            ko.exportProperty(computedFn, 'getDependencies', computedFn.getDependencies);\n\n            ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {\n                if (typeof evaluatorFunctionOrOptions === 'function') {\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});\n                } else {\n                    evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object\n                    evaluatorFunctionOrOptions['pure'] = true;\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);\n                }\n            }\n            ko.exportSymbol('pureComputed', ko.pureComputed);\n\n            (function() {\n                var maxNestedObservableDepth = 10; // Escape the (unlikely) pathological case where an observable's current value is itself (or similar reference cycle)\n\n                ko.toJS = function(rootObject) {\n                    if (arguments.length == 0)\n                        throw new Error(\"When calling ko.toJS, pass the object you want to convert.\");\n\n                    // We just unwrap everything at every level in the object graph\n                    return mapJsObjectGraph(rootObject, function(valueToMap) {\n                        // Loop because an observable's value might in turn be another observable wrapper\n                        for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)\n                            valueToMap = valueToMap();\n                        return valueToMap;\n                    });\n                };\n\n                ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional\n                    var plainJavaScriptObject = ko.toJS(rootObject);\n                    return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);\n                };\n\n                function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {\n                    visitedObjects = visitedObjects || new objectLookup();\n\n                    rootObject = mapInputCallback(rootObject);\n                    var canHaveProperties = (typeof rootObject == \"object\") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof RegExp)) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));\n                    if (!canHaveProperties)\n                        return rootObject;\n\n                    var outputProperties = rootObject instanceof Array ? [] : {};\n                    visitedObjects.save(rootObject, outputProperties);\n\n                    visitPropertiesOrArrayEntries(rootObject, function(indexer) {\n                        var propertyValue = mapInputCallback(rootObject[indexer]);\n\n                        switch (typeof propertyValue) {\n                            case \"boolean\":\n                            case \"number\":\n                            case \"string\":\n                            case \"function\":\n                                outputProperties[indexer] = propertyValue;\n                                break;\n                            case \"object\":\n                            case \"undefined\":\n                                var previouslyMappedValue = visitedObjects.get(propertyValue);\n                                outputProperties[indexer] = (previouslyMappedValue !== undefined)\n                                    ? previouslyMappedValue\n                                    : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);\n                                break;\n                        }\n                    });\n\n                    return outputProperties;\n                }\n\n                function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {\n                    if (rootObject instanceof Array) {\n                        for (var i = 0; i < rootObject.length; i++)\n                            visitorCallback(i);\n\n                        // For arrays, also respect toJSON property for custom mappings (fixes #278)\n                        if (typeof rootObject['toJSON'] == 'function')\n                            visitorCallback('toJSON');\n                    } else {\n                        for (var propertyName in rootObject) {\n                            visitorCallback(propertyName);\n                        }\n                    }\n                };\n\n                function objectLookup() {\n                    this.keys = [];\n                    this.values = [];\n                };\n\n                objectLookup.prototype = {\n                    constructor: objectLookup,\n                    save: function(key, value) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        if (existingIndex >= 0)\n                            this.values[existingIndex] = value;\n                        else {\n                            this.keys.push(key);\n                            this.values.push(value);\n                        }\n                    },\n                    get: function(key) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        return (existingIndex >= 0) ? this.values[existingIndex] : undefined;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('toJS', ko.toJS);\n            ko.exportSymbol('toJSON', ko.toJSON);\n            ko.when = function(predicate, callback, context) {\n                function kowhen (resolve) {\n                    var observable = ko.pureComputed(predicate, context).extend({notify:'always'});\n                    var subscription = observable.subscribe(function(value) {\n                        if (value) {\n                            subscription.dispose();\n                            resolve(value);\n                        }\n                    });\n                    // In case the initial value is true, process it right away\n                    observable['notifySubscribers'](observable.peek());\n\n                    return subscription;\n                }\n                if (typeof Promise === \"function\" && !callback) {\n                    return new Promise(kowhen);\n                } else {\n                    return kowhen(callback.bind(context));\n                }\n            };\n\n            ko.exportSymbol('when', ko.when);\n            (function () {\n                var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';\n\n                // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values\n                // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values\n                // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.\n                ko.selectExtensions = {\n                    readValue : function(element) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (element[hasDomDataExpandoProperty] === true)\n                                    return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);\n                                return ko.utils.ieVersion <= 7\n                                    ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)\n                                    : element.value;\n                            case 'select':\n                                return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;\n                            default:\n                                return element.value;\n                        }\n                    },\n\n                    writeValue: function(element, value, allowUnset) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (typeof value === \"string\") {\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);\n                                    if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node\n                                        delete element[hasDomDataExpandoProperty];\n                                    }\n                                    element.value = value;\n                                }\n                                else {\n                                    // Store arbitrary object using DomData\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);\n                                    element[hasDomDataExpandoProperty] = true;\n\n                                    // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.\n                                    element.value = typeof value === \"number\" ? value : \"\";\n                                }\n                                break;\n                            case 'select':\n                                if (value === \"\" || value === null)       // A blank string or null value will select the caption\n                                    value = undefined;\n                                var selection = -1;\n                                for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {\n                                    optionValue = ko.selectExtensions.readValue(element.options[i]);\n                                    // Include special check to handle selecting a caption with a blank string value\n                                    if (optionValue == value || (optionValue === \"\" && value === undefined)) {\n                                        selection = i;\n                                        break;\n                                    }\n                                }\n                                if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {\n                                    element.selectedIndex = selection;\n                                    if (ko.utils.ieVersion === 6) {\n                                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread\n                                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread\n                                        // to apply the value as well.\n                                        ko.utils.setTimeout(function () {\n                                            element.selectedIndex = selection;\n                                        }, 0);\n                                    }\n                                }\n                                break;\n                            default:\n                                if ((value === null) || (value === undefined))\n                                    value = \"\";\n                                element.value = value;\n                                break;\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('selectExtensions', ko.selectExtensions);\n            ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);\n            ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);\n            ko.expressionRewriting = (function () {\n                var javaScriptReservedWords = [\"true\", \"false\", \"null\", \"undefined\"];\n\n                // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor\n                // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).\n                // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).\n                var javaScriptAssignmentTarget = /^(?:[$_a-z][$\\w]*|(.+)(\\.\\s*[$_a-z][$\\w]*|\\[.+\\]))$/i;\n\n                function getWriteableValue(expression) {\n                    if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)\n                        return false;\n                    var match = expression.match(javaScriptAssignmentTarget);\n                    return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;\n                }\n\n                // The following regular expressions will be used to split an object-literal string into tokens\n\n                var specials = ',\"\\'`{}()/:[\\\\]',    // These characters have special meaning to the parser and must not appear in the middle of a token, except as part of a string.\n                    // Create the actual regular expression by or-ing the following regex strings. The order is important.\n                    bindingToken = RegExp([\n                        // These match strings, either with double quotes, single quotes, or backticks\n                        '\"(?:\\\\\\\\.|[^\"])*\"',\n                        \"'(?:\\\\\\\\.|[^'])*'\",\n                        \"`(?:\\\\\\\\.|[^`])*`\",\n                        // Match C style comments\n                        \"/\\\\*(?:[^*]|\\\\*+[^*/])*\\\\*+/\",\n                        // Match C++ style comments\n                        \"//.*\\n\",\n                        // Match a regular expression (text enclosed by slashes), but will also match sets of divisions\n                        // as a regular expression (this is handled by the parsing loop below).\n                        '/(?:\\\\\\\\.|[^/])+/\\w*',\n                        // Match text (at least two characters) that does not contain any of the above special characters,\n                        // although some of the special characters are allowed to start it (all but the colon and comma).\n                        // The text can contain spaces, but leading or trailing spaces are skipped.\n                        '[^\\\\s:,/][^' + specials + ']*[^\\\\s' + specials + ']',\n                        // Match any non-space character not matched already. This will match colons and commas, since they're\n                        // not matched by \"everyThingElse\", but will also match any other single character that wasn't already\n                        // matched (for example: in \"a: 1, b: 2\", each of the non-space characters will be matched by oneNotSpace).\n                        '[^\\\\s]'\n                    ].join('|'), 'g'),\n\n                    // Match end of previous token to determine whether a slash is a division or regex.\n                    divisionLookBehind = /[\\])\"'A-Za-z0-9_$]+$/,\n                    keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};\n\n                function parseObjectLiteral(objectLiteralString) {\n                    // Trim leading and trailing spaces from the string\n                    var str = ko.utils.stringTrim(objectLiteralString);\n\n                    // Trim braces '{' surrounding the whole object literal\n                    if (str.charCodeAt(0) === 123) str = str.slice(1, -1);\n\n                    // Add a newline to correctly match a C++ style comment at the end of the string and\n                    // add a comma so that we don't need a separate code block to deal with the last item\n                    str += \"\\n,\";\n\n                    // Split into tokens\n                    var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;\n\n                    if (toks.length > 1) {\n                        for (var i = 0, tok; tok = toks[i]; ++i) {\n                            var c = tok.charCodeAt(0);\n                            // A comma signals the end of a key/value pair if depth is zero\n                            if (c === 44) { // \",\"\n                                if (depth <= 0) {\n                                    result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});\n                                    key = depth = 0;\n                                    values = [];\n                                    continue;\n                                }\n                                // Simply skip the colon that separates the name and value\n                            } else if (c === 58) { // \":\"\n                                if (!depth && !key && values.length === 1) {\n                                    key = values.pop();\n                                    continue;\n                                }\n                                // Comments: skip them\n                            } else if (c === 47 && tok.length > 1 && (tok.charCodeAt(1) === 47 || tok.charCodeAt(1) === 42)) {  // \"//\" or \"/*\"\n                                continue;\n                                // A set of slashes is initially matched as a regular expression, but could be division\n                            } else if (c === 47 && i && tok.length > 1) {  // \"/\"\n                                // Look at the end of the previous token to determine if the slash is actually division\n                                var match = toks[i-1].match(divisionLookBehind);\n                                if (match && !keywordRegexLookBehind[match[0]]) {\n                                    // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)\n                                    str = str.substr(str.indexOf(tok) + 1);\n                                    toks = str.match(bindingToken);\n                                    i = -1;\n                                    // Continue with just the slash\n                                    tok = '/';\n                                }\n                                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored\n                            } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['\n                                ++depth;\n                            } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'\n                                --depth;\n                                // The key will be the first token; if it's a string, trim the quotes\n                            } else if (!key && !values.length && (c === 34 || c === 39)) { // '\"', \"'\"\n                                tok = tok.slice(1, -1);\n                            }\n                            values.push(tok);\n                        }\n                        if (depth > 0) {\n                            throw Error(\"Unbalanced parentheses, braces, or brackets\");\n                        }\n                    }\n                    return result;\n                }\n\n                // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.\n                var twoWayBindings = {};\n\n                function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {\n                    bindingOptions = bindingOptions || {};\n\n                    function processKeyValue(key, val) {\n                        var writableVal;\n                        function callPreprocessHook(obj) {\n                            return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;\n                        }\n                        if (!bindingParams) {\n                            if (!callPreprocessHook(ko['getBindingHandler'](key)))\n                                return;\n\n                            if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {\n                                // For two-way bindings, provide a write method in case the value\n                                // isn't a writable observable.\n                                var writeKey = typeof twoWayBindings[key] == 'string' ? twoWayBindings[key] : key;\n                                propertyAccessorResultStrings.push(\"'\" + writeKey + \"':function(_z){\" + writableVal + \"=_z}\");\n                            }\n                        }\n                        // Values are wrapped in a function so that each value can be accessed independently\n                        if (makeValueAccessors) {\n                            val = 'function(){return ' + val + ' }';\n                        }\n                        resultStrings.push(\"'\" + key + \"':\" + val);\n                    }\n\n                    var resultStrings = [],\n                        propertyAccessorResultStrings = [],\n                        makeValueAccessors = bindingOptions['valueAccessors'],\n                        bindingParams = bindingOptions['bindingParams'],\n                        keyValueArray = typeof bindingsStringOrKeyValueArray === \"string\" ?\n                            parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;\n\n                    ko.utils.arrayForEach(keyValueArray, function(keyValue) {\n                        processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);\n                    });\n\n                    if (propertyAccessorResultStrings.length)\n                        processKeyValue('_ko_property_writers', \"{\" + propertyAccessorResultStrings.join(\",\") + \" }\");\n\n                    return resultStrings.join(\",\");\n                }\n\n                return {\n                    bindingRewriteValidators: [],\n\n                    twoWayBindings: twoWayBindings,\n\n                    parseObjectLiteral: parseObjectLiteral,\n\n                    preProcessBindings: preProcessBindings,\n\n                    keyValueArrayContainsKey: function(keyValueArray, key) {\n                        for (var i = 0; i < keyValueArray.length; i++)\n                            if (keyValueArray[i]['key'] == key)\n                                return true;\n                        return false;\n                    },\n\n                    // Internal, private KO utility for updating model properties from within bindings\n                    // property:            If the property being updated is (or might be) an observable, pass it here\n                    //                      If it turns out to be a writable observable, it will be written to directly\n                    // allBindings:         An object with a get method to retrieve bindings in the current execution context.\n                    //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable\n                    // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'\n                    // value:               The value to be written\n                    // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if\n                    //                      it is !== existing value on that writable observable\n                    writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {\n                        if (!property || !ko.isObservable(property)) {\n                            var propWriters = allBindings.get('_ko_property_writers');\n                            if (propWriters && propWriters[key])\n                                propWriters[key](value);\n                        } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {\n                            property(value);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('expressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);\n            ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);\n            ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);\n\n// Making bindings explicitly declare themselves as \"two way\" isn't ideal in the long term (it would be better if\n// all bindings could use an official 'property writer' API without needing to declare that they might). However,\n// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable\n// as an internal implementation detail in the short term.\n// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an\n// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official\n// public API, and we reserve the right to remove it at any time if we create a real public property writers API.\n            ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);\n\n// For backward compatibility, define the following aliases. (Previously, these function names were misleading because\n// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)\n            ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);\n            (function() {\n                // \"Virtual elements\" is an abstraction on top of the usual DOM API which understands the notion that comment nodes\n                // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).\n                // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state\n                // of that virtual hierarchy\n                //\n                // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)\n                // without having to scatter special cases all over the binding and templating code.\n\n                // IE 9 cannot reliably read the \"nodeValue\" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)\n                // but it does give them a nonstandard alternative property called \"text\" that it can read reliably. Other browsers don't have that property.\n                // So, use node.text where available, and node.nodeValue elsewhere\n                var commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\n\n                var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\n                var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\\s*\\/ko\\s*-->$/ : /^\\s*\\/ko\\s*$/;\n                var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };\n\n                function isStartComment(node) {\n                    return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isEndComment(node) {\n                    return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isUnmatchedEndComment(node) {\n                    return isEndComment(node) && !(ko.utils.domData.get(node, matchedEndCommentDataKey));\n                }\n\n                var matchedEndCommentDataKey = \"__ko_matchedEndComment__\"\n\n                function getVirtualChildren(startComment, allowUnbalanced) {\n                    var currentNode = startComment;\n                    var depth = 1;\n                    var children = [];\n                    while (currentNode = currentNode.nextSibling) {\n                        if (isEndComment(currentNode)) {\n                            ko.utils.domData.set(currentNode, matchedEndCommentDataKey, true);\n                            depth--;\n                            if (depth === 0)\n                                return children;\n                        }\n\n                        children.push(currentNode);\n\n                        if (isStartComment(currentNode))\n                            depth++;\n                    }\n                    if (!allowUnbalanced)\n                        throw new Error(\"Cannot find closing comment tag to match: \" + startComment.nodeValue);\n                    return null;\n                }\n\n                function getMatchingEndComment(startComment, allowUnbalanced) {\n                    var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);\n                    if (allVirtualChildren) {\n                        if (allVirtualChildren.length > 0)\n                            return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;\n                        return startComment.nextSibling;\n                    } else\n                        return null; // Must have no matching end comment, and allowUnbalanced is true\n                }\n\n                function getUnbalancedChildTags(node) {\n                    // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>\n                    //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->\n                    var childNode = node.firstChild, captureRemaining = null;\n                    if (childNode) {\n                        do {\n                            if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes\n                                captureRemaining.push(childNode);\n                            else if (isStartComment(childNode)) {\n                                var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);\n                                if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set\n                                    childNode = matchingEndComment;\n                                else\n                                    captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point\n                            } else if (isEndComment(childNode)) {\n                                captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing\n                            }\n                        } while (childNode = childNode.nextSibling);\n                    }\n                    return captureRemaining;\n                }\n\n                ko.virtualElements = {\n                    allowedBindings: {},\n\n                    childNodes: function(node) {\n                        return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;\n                    },\n\n                    emptyNode: function(node) {\n                        if (!isStartComment(node))\n                            ko.utils.emptyDomNode(node);\n                        else {\n                            var virtualChildren = ko.virtualElements.childNodes(node);\n                            for (var i = 0, j = virtualChildren.length; i < j; i++)\n                                ko.removeNode(virtualChildren[i]);\n                        }\n                    },\n\n                    setDomNodeChildren: function(node, childNodes) {\n                        if (!isStartComment(node))\n                            ko.utils.setDomNodeChildren(node, childNodes);\n                        else {\n                            ko.virtualElements.emptyNode(node);\n                            var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);\n                        }\n                    },\n\n                    prepend: function(containerNode, nodeToPrepend) {\n                        var insertBeforeNode;\n\n                        if (isStartComment(containerNode)) {\n                            // Start comments must always have a parent and at least one following sibling (the end comment)\n                            insertBeforeNode = containerNode.nextSibling;\n                            containerNode = containerNode.parentNode;\n                        } else {\n                            insertBeforeNode = containerNode.firstChild;\n                        }\n\n                        if (!insertBeforeNode) {\n                            containerNode.appendChild(nodeToPrepend);\n                        } else if (nodeToPrepend !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                            containerNode.insertBefore(nodeToPrepend, insertBeforeNode);\n                        }\n                    },\n\n                    insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {\n                        if (!insertAfterNode) {\n                            ko.virtualElements.prepend(containerNode, nodeToInsert);\n                        } else {\n                            // Children of start comments must always have a parent and at least one following sibling (the end comment)\n                            var insertBeforeNode = insertAfterNode.nextSibling;\n\n                            if (isStartComment(containerNode)) {\n                                containerNode = containerNode.parentNode;\n                            }\n\n                            if (!insertBeforeNode) {\n                                containerNode.appendChild(nodeToInsert);\n                            } else if (nodeToInsert !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                                containerNode.insertBefore(nodeToInsert, insertBeforeNode);\n                            }\n                        }\n                    },\n\n                    firstChild: function(node) {\n                        if (!isStartComment(node)) {\n                            if (node.firstChild && isEndComment(node.firstChild)) {\n                                throw new Error(\"Found invalid end comment, as the first child of \" + node);\n                            }\n                            return node.firstChild;\n                        } else if (!node.nextSibling || isEndComment(node.nextSibling)) {\n                            return null;\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    nextSibling: function(node) {\n                        if (isStartComment(node)) {\n                            node = getMatchingEndComment(node);\n                        }\n\n                        if (node.nextSibling && isEndComment(node.nextSibling)) {\n                            if (isUnmatchedEndComment(node.nextSibling)) {\n                                throw Error(\"Found end comment without a matching opening comment, as child of \" + node);\n                            } else {\n                                return null;\n                            }\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    hasBindingValue: isStartComment,\n\n                    virtualNodeBindingValue: function(node) {\n                        var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);\n                        return regexMatch ? regexMatch[1] : null;\n                    },\n\n                    normaliseVirtualElementDomStructure: function(elementVerified) {\n                        // Workaround for https://github.com/SteveSanderson/knockout/issues/155\n                        // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes\n                        // that are direct descendants of <ul> into the preceding <li>)\n                        if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])\n                            return;\n\n                        // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags\n                        // must be intended to appear *after* that child, so move them there.\n                        var childNode = elementVerified.firstChild;\n                        if (childNode) {\n                            do {\n                                if (childNode.nodeType === 1) {\n                                    var unbalancedTags = getUnbalancedChildTags(childNode);\n                                    if (unbalancedTags) {\n                                        // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child\n                                        var nodeToInsertBefore = childNode.nextSibling;\n                                        for (var i = 0; i < unbalancedTags.length; i++) {\n                                            if (nodeToInsertBefore)\n                                                elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);\n                                            else\n                                                elementVerified.appendChild(unbalancedTags[i]);\n                                        }\n                                    }\n                                }\n                            } while (childNode = childNode.nextSibling);\n                        }\n                    }\n                };\n            })();\n            ko.exportSymbol('virtualElements', ko.virtualElements);\n            ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);\n            ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);\n//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified\n            ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);\n//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified\n            ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);\n            ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);\n            (function() {\n                var defaultBindingAttributeName = \"data-bind\";\n\n                ko.bindingProvider = function() {\n                    this.bindingCache = {};\n                };\n\n                ko.utils.extend(ko.bindingProvider.prototype, {\n                    'nodeHasBindings': function(node) {\n                        switch (node.nodeType) {\n                            case 1: // Element\n                                return node.getAttribute(defaultBindingAttributeName) != null\n                                    || ko.components['getComponentNameForNode'](node);\n                            case 8: // Comment node\n                                return ko.virtualElements.hasBindingValue(node);\n                            default: return false;\n                        }\n                    },\n\n                    'getBindings': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);\n                    },\n\n                    'getBindingAccessors': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'getBindingsString': function(node, bindingContext) {\n                        switch (node.nodeType) {\n                            case 1: return node.getAttribute(defaultBindingAttributeName);   // Element\n                            case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node\n                            default: return null;\n                        }\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'parseBindingsString': function(bindingsString, bindingContext, node, options) {\n                        try {\n                            var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);\n                            return bindingFunction(bindingContext, node);\n                        } catch (ex) {\n                            ex.message = \"Unable to parse bindings.\\nBindings value: \" + bindingsString + \"\\nMessage: \" + ex.message;\n                            throw ex;\n                        }\n                    }\n                });\n\n                ko.bindingProvider['instance'] = new ko.bindingProvider();\n\n                function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {\n                    var cacheKey = bindingsString + (options && options['valueAccessors'] || '');\n                    return cache[cacheKey]\n                        || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));\n                }\n\n                function createBindingsStringEvaluator(bindingsString, options) {\n                    // Build the source for a function that evaluates \"expression\"\n                    // For each scope variable, add an extra level of \"with\" nesting\n                    // Example result: with(sc1) { with(sc0) { return (expression) } }\n                    var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),\n                        functionBody = \"with($context){with($data||{}){return{\" + rewrittenBindings + \"}}}\";\n                    return new Function(\"$context\", \"$element\", functionBody);\n                }\n            })();\n\n            ko.exportSymbol('bindingProvider', ko.bindingProvider);\n            (function () {\n                // Hide or don't minify context properties, see https://github.com/knockout/knockout/issues/2294\n                var contextSubscribable = ko.utils.createSymbolOrString('_subscribable');\n                var contextAncestorBindingInfo = ko.utils.createSymbolOrString('_ancestorBindingInfo');\n                var contextDataDependency = ko.utils.createSymbolOrString('_dataDependency');\n\n                ko.bindingHandlers = {};\n\n                // The following element types will not be recursed into during binding.\n                var bindingDoesNotRecurseIntoElementTypes = {\n                    // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,\n                    // because it's unexpected and a potential XSS issue.\n                    // Also bindings should not operate on <template> elements since this breaks in Internet Explorer\n                    // and because such elements' contents are always intended to be bound in a different context\n                    // from where they appear in the document.\n                    'script': true,\n                    'textarea': true,\n                    'template': true\n                };\n\n                // Use an overridable method for retrieving binding handlers so that plugins may support dynamically created handlers\n                ko['getBindingHandler'] = function(bindingKey) {\n                    return ko.bindingHandlers[bindingKey];\n                };\n\n                var inheritParentVm = {};\n\n                // The ko.bindingContext constructor is only called directly to create the root context. For child\n                // contexts, use bindingContext.createChildContext or bindingContext.extend.\n                ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, options) {\n\n                    // The binding context object includes static properties for the current, parent, and root view models.\n                    // If a view model is actually stored in an observable, the corresponding binding context object, and\n                    // any child contexts, must be updated when the view model is changed.\n                    function updateContext() {\n                        // Most of the time, the context will directly get a view model object, but if a function is given,\n                        // we call the function to retrieve the view model. If the function accesses any observables or returns\n                        // an observable, the dependency is tracked, and those observables can later cause the binding\n                        // context to be updated.\n                        var dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor,\n                            dataItem = ko.utils.unwrapObservable(dataItemOrObservable);\n\n                        if (parentContext) {\n                            // Copy $root and any custom properties from the parent context\n                            ko.utils.extend(self, parentContext);\n\n                            // Copy Symbol properties\n                            if (contextAncestorBindingInfo in parentContext) {\n                                self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo];\n                            }\n                        } else {\n                            self['$parents'] = [];\n                            self['$root'] = dataItem;\n\n                            // Export 'ko' in the binding context so it will be available in bindings and templates\n                            // even if 'ko' isn't exported as a global, such as when using an AMD loader.\n                            // See https://github.com/SteveSanderson/knockout/issues/490\n                            self['ko'] = ko;\n                        }\n\n                        self[contextSubscribable] = subscribable;\n\n                        if (shouldInheritData) {\n                            dataItem = self['$data'];\n                        } else {\n                            self['$rawData'] = dataItemOrObservable;\n                            self['$data'] = dataItem;\n                        }\n\n                        if (dataItemAlias)\n                            self[dataItemAlias] = dataItem;\n\n                        // The extendCallback function is provided when creating a child context or extending a context.\n                        // It handles the specific actions needed to finish setting up the binding context. Actions in this\n                        // function could also add dependencies to this binding context.\n                        if (extendCallback)\n                            extendCallback(self, parentContext, dataItem);\n\n                        // When a \"parent\" context is given and we don't already have a dependency on its context, register a dependency on it.\n                        // Thus whenever the parent context is updated, this context will also be updated.\n                        if (parentContext && parentContext[contextSubscribable] && !ko.computedContext.computed().hasAncestorDependency(parentContext[contextSubscribable])) {\n                            parentContext[contextSubscribable]();\n                        }\n\n                        if (dataDependency) {\n                            self[contextDataDependency] = dataDependency;\n                        }\n\n                        return self['$data'];\n                    }\n\n                    var self = this,\n                        shouldInheritData = dataItemOrAccessor === inheritParentVm,\n                        realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,\n                        isFunc = typeof(realDataItemOrAccessor) == \"function\" && !ko.isObservable(realDataItemOrAccessor),\n                        nodes,\n                        subscribable,\n                        dataDependency = options && options['dataDependency'];\n\n                    if (options && options['exportDependencies']) {\n                        // The \"exportDependencies\" option means that the calling code will track any dependencies and re-create\n                        // the binding context when they change.\n                        updateContext();\n                    } else {\n                        subscribable = ko.pureComputed(updateContext);\n                        subscribable.peek();\n\n                        // At this point, the binding context has been initialized, and the \"subscribable\" computed observable is\n                        // subscribed to any observables that were accessed in the process. If there is nothing to track, the\n                        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in\n                        // the context object.\n                        if (subscribable.isActive()) {\n                            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed\n                            subscribable['equalityComparer'] = null;\n                        } else {\n                            self[contextSubscribable] = undefined;\n                        }\n                    }\n                }\n\n                // Extend the binding context hierarchy with a new view model object. If the parent context is watching\n                // any observables, the new child context will automatically get a dependency on the parent context.\n                // But this does not mean that the $data value of the child context will also get updated. If the child\n                // view model also depends on the parent view model, you must provide a function that returns the correct\n                // view model on each update.\n                ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback, options) {\n                    if (!options && dataItemAlias && typeof dataItemAlias == \"object\") {\n                        options = dataItemAlias;\n                        dataItemAlias = options['as'];\n                        extendCallback = options['extend'];\n                    }\n\n                    if (dataItemAlias && options && options['noChildContext']) {\n                        var isFunc = typeof(dataItemOrAccessor) == \"function\" && !ko.isObservable(dataItemOrAccessor);\n                        return new ko.bindingContext(inheritParentVm, this, null, function (self) {\n                            if (extendCallback)\n                                extendCallback(self);\n                            self[dataItemAlias] = isFunc ? dataItemOrAccessor() : dataItemOrAccessor;\n                        }, options);\n                    }\n\n                    return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function (self, parentContext) {\n                        // Extend the context hierarchy by setting the appropriate pointers\n                        self['$parentContext'] = parentContext;\n                        self['$parent'] = parentContext['$data'];\n                        self['$parents'] = (parentContext['$parents'] || []).slice(0);\n                        self['$parents'].unshift(self['$parent']);\n                        if (extendCallback)\n                            extendCallback(self);\n                    }, options);\n                };\n\n                // Extend the binding context with new custom properties. This doesn't change the context hierarchy.\n                // Similarly to \"child\" contexts, provide a function here to make sure that the correct values are set\n                // when an observable view model is updated.\n                ko.bindingContext.prototype['extend'] = function(properties, options) {\n                    return new ko.bindingContext(inheritParentVm, this, null, function(self, parentContext) {\n                        ko.utils.extend(self, typeof(properties) == \"function\" ? properties(self) : properties);\n                    }, options);\n                };\n\n                var boundElementDomDataKey = ko.utils.domData.nextKey();\n\n                function asyncContextDispose(node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey),\n                        asyncContext = bindingInfo && bindingInfo.asyncContext;\n                    if (asyncContext) {\n                        bindingInfo.asyncContext = null;\n                        asyncContext.notifyAncestor();\n                    }\n                }\n                function AsyncCompleteContext(node, bindingInfo, ancestorBindingInfo) {\n                    this.node = node;\n                    this.bindingInfo = bindingInfo;\n                    this.asyncDescendants = [];\n                    this.childrenComplete = false;\n\n                    if (!bindingInfo.asyncContext) {\n                        ko.utils.domNodeDisposal.addDisposeCallback(node, asyncContextDispose);\n                    }\n\n                    if (ancestorBindingInfo && ancestorBindingInfo.asyncContext) {\n                        ancestorBindingInfo.asyncContext.asyncDescendants.push(node);\n                        this.ancestorBindingInfo = ancestorBindingInfo;\n                    }\n                }\n                AsyncCompleteContext.prototype.notifyAncestor = function () {\n                    if (this.ancestorBindingInfo && this.ancestorBindingInfo.asyncContext) {\n                        this.ancestorBindingInfo.asyncContext.descendantComplete(this.node);\n                    }\n                };\n                AsyncCompleteContext.prototype.descendantComplete = function (node) {\n                    ko.utils.arrayRemoveItem(this.asyncDescendants, node);\n                    if (!this.asyncDescendants.length && this.childrenComplete) {\n                        this.completeChildren();\n                    }\n                };\n                AsyncCompleteContext.prototype.completeChildren = function () {\n                    this.childrenComplete = true;\n                    if (this.bindingInfo.asyncContext && !this.asyncDescendants.length) {\n                        this.bindingInfo.asyncContext = null;\n                        ko.utils.domNodeDisposal.removeDisposeCallback(this.node, asyncContextDispose);\n                        ko.bindingEvent.notify(this.node, ko.bindingEvent.descendantsComplete);\n                        this.notifyAncestor();\n                    }\n                };\n\n                ko.bindingEvent = {\n                    childrenComplete: \"childrenComplete\",\n                    descendantsComplete : \"descendantsComplete\",\n\n                    subscribe: function (node, event, callback, context, options) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n                        if (!bindingInfo.eventSubscribable) {\n                            bindingInfo.eventSubscribable = new ko.subscribable;\n                        }\n                        if (options && options['notifyImmediately'] && bindingInfo.notifiedEvents[event]) {\n                            ko.dependencyDetection.ignore(callback, context, [node]);\n                        }\n                        return bindingInfo.eventSubscribable.subscribe(callback, context, event);\n                    },\n\n                    notify: function (node, event) {\n                        var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                        if (bindingInfo) {\n                            bindingInfo.notifiedEvents[event] = true;\n                            if (bindingInfo.eventSubscribable) {\n                                bindingInfo.eventSubscribable['notifySubscribers'](node, event);\n                            }\n                            if (event == ko.bindingEvent.childrenComplete) {\n                                if (bindingInfo.asyncContext) {\n                                    bindingInfo.asyncContext.completeChildren();\n                                } else if (bindingInfo.asyncContext === undefined && bindingInfo.eventSubscribable && bindingInfo.eventSubscribable.hasSubscriptionsForEvent(ko.bindingEvent.descendantsComplete)) {\n                                    // It's currently an error to register a descendantsComplete handler for a node that was never registered as completing asynchronously.\n                                    // That's because without the asyncContext, we don't have a way to know that all descendants have completed.\n                                    throw new Error(\"descendantsComplete event not supported for bindings on this node\");\n                                }\n                            }\n                        }\n                    },\n\n                    startPossiblyAsyncContentBinding: function (node, bindingContext) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                        if (!bindingInfo.asyncContext) {\n                            bindingInfo.asyncContext = new AsyncCompleteContext(node, bindingInfo, bindingContext[contextAncestorBindingInfo]);\n                        }\n\n                        // If the provided context was already extended with this node's binding info, just return the extended context\n                        if (bindingContext[contextAncestorBindingInfo] == bindingInfo) {\n                            return bindingContext;\n                        }\n\n                        return bindingContext['extend'](function (ctx) {\n                            ctx[contextAncestorBindingInfo] = bindingInfo;\n                        });\n                    }\n                };\n\n                // Returns the valueAccessor function for a binding value\n                function makeValueAccessor(value) {\n                    return function() {\n                        return value;\n                    };\n                }\n\n                // Returns the value of a valueAccessor function\n                function evaluateValueAccessor(valueAccessor) {\n                    return valueAccessor();\n                }\n\n                // Given a function that returns bindings, create and return a new object that contains\n                // binding value-accessors functions. Each accessor function calls the original function\n                // so that it always gets the latest value and all dependencies are captured. This is used\n                // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.\n                function makeAccessorsFromFunction(callback) {\n                    return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {\n                        return function() {\n                            return callback()[key];\n                        };\n                    });\n                }\n\n                // Given a bindings function or object, create and return a new object that contains\n                // binding value-accessors functions. This is used by ko.applyBindingsToNode.\n                function makeBindingAccessors(bindings, context, node) {\n                    if (typeof bindings === 'function') {\n                        return makeAccessorsFromFunction(bindings.bind(null, context, node));\n                    } else {\n                        return ko.utils.objectMap(bindings, makeValueAccessor);\n                    }\n                }\n\n                // This function is used if the binding provider doesn't include a getBindingAccessors function.\n                // It must be called with 'this' set to the provider instance.\n                function getBindingsAndMakeAccessors(node, context) {\n                    return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));\n                }\n\n                function validateThatBindingIsAllowedForVirtualElements(bindingName) {\n                    var validator = ko.virtualElements.allowedBindings[bindingName];\n                    if (!validator)\n                        throw new Error(\"The binding '\" + bindingName + \"' cannot be used with virtual elements\")\n                }\n\n                function applyBindingsToDescendantsInternal(bindingContext, elementOrVirtualElement) {\n                    var nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n\n                    if (nextInQueue) {\n                        var currentChild,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's\n                        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to\n                        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that\n                        // trigger insertion of <template> contents at that point in the document.\n                        if (preprocessNode) {\n                            while (currentChild = nextInQueue) {\n                                nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                                preprocessNode.call(provider, currentChild);\n                            }\n                            // Reset nextInQueue for the next loop\n                            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n                        }\n\n                        while (currentChild = nextInQueue) {\n                            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position\n                            nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild);\n                        }\n                    }\n                    ko.bindingEvent.notify(elementOrVirtualElement, ko.bindingEvent.childrenComplete);\n                }\n\n                function applyBindingsToNodeAndDescendantsInternal(bindingContext, nodeVerified) {\n                    var bindingContextForDescendants = bindingContext;\n\n                    var isElement = (nodeVerified.nodeType === 1);\n                    if (isElement) // Workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);\n\n                    // Perf optimisation: Apply bindings only if...\n                    // (1) We need to store the binding info for the node (all element nodes)\n                    // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)\n                    var shouldApplyBindings = isElement || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);\n                    if (shouldApplyBindings)\n                        bindingContextForDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext)['bindingContextForDescendants'];\n\n                    if (bindingContextForDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {\n                        applyBindingsToDescendantsInternal(bindingContextForDescendants, nodeVerified);\n                    }\n                }\n\n                function topologicalSortBindings(bindings) {\n                    // Depth-first sort\n                    var result = [],                // The list of key/handler pairs that we will return\n                        bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'\n                        cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it\n                    ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {\n                        if (!bindingsConsidered[bindingKey]) {\n                            var binding = ko['getBindingHandler'](bindingKey);\n                            if (binding) {\n                                // First add dependencies (if any) of the current binding\n                                if (binding['after']) {\n                                    cyclicDependencyStack.push(bindingKey);\n                                    ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {\n                                        if (bindings[bindingDependencyKey]) {\n                                            if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {\n                                                throw Error(\"Cannot combine the following bindings, because they have a cyclic dependency: \" + cyclicDependencyStack.join(\", \"));\n                                            } else {\n                                                pushBinding(bindingDependencyKey);\n                                            }\n                                        }\n                                    });\n                                    cyclicDependencyStack.length--;\n                                }\n                                // Next add the current binding\n                                result.push({ key: bindingKey, handler: binding });\n                            }\n                            bindingsConsidered[bindingKey] = true;\n                        }\n                    });\n\n                    return result;\n                }\n\n                function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {\n                    var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                    // Prevent multiple applyBindings calls for the same node, except when a binding value is specified\n                    var alreadyBound = bindingInfo.alreadyBound;\n                    if (!sourceBindings) {\n                        if (alreadyBound) {\n                            throw Error(\"You cannot apply bindings multiple times to the same element.\");\n                        }\n                        bindingInfo.alreadyBound = true;\n                    }\n                    if (!alreadyBound) {\n                        bindingInfo.context = bindingContext;\n                    }\n                    if (!bindingInfo.notifiedEvents) {\n                        bindingInfo.notifiedEvents = {};\n                    }\n\n                    // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings\n                    var bindings;\n                    if (sourceBindings && typeof sourceBindings !== 'function') {\n                        bindings = sourceBindings;\n                    } else {\n                        var provider = ko.bindingProvider['instance'],\n                            getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;\n\n                        // Get the binding from the provider within a computed observable so that we can update the bindings whenever\n                        // the binding context is updated or if the binding provider accesses observables.\n                        var bindingsUpdater = ko.dependentObservable(\n                            function() {\n                                bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);\n                                // Register a dependency on the binding context to support observable view models.\n                                if (bindings) {\n                                    if (bindingContext[contextSubscribable]) {\n                                        bindingContext[contextSubscribable]();\n                                    }\n                                    if (bindingContext[contextDataDependency]) {\n                                        bindingContext[contextDataDependency]();\n                                    }\n                                }\n                                return bindings;\n                            },\n                            null, { disposeWhenNodeIsRemoved: node }\n                        );\n\n                        if (!bindings || !bindingsUpdater.isActive())\n                            bindingsUpdater = null;\n                    }\n\n                    var contextToExtend = bindingContext;\n                    var bindingHandlerThatControlsDescendantBindings;\n                    if (bindings) {\n                        // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding\n                        // context update), just return the value accessor from the binding. Otherwise, return a function that always gets\n                        // the latest binding value and registers a dependency on the binding updater.\n                        var getValueAccessor = bindingsUpdater\n                            ? function(bindingKey) {\n                                return function() {\n                                    return evaluateValueAccessor(bindingsUpdater()[bindingKey]);\n                                };\n                            } : function(bindingKey) {\n                                return bindings[bindingKey];\n                            };\n\n                        // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated\n                        function allBindings() {\n                            return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);\n                        }\n                        // The following is the 3.x allBindings API\n                        allBindings['get'] = function(key) {\n                            return bindings[key] && evaluateValueAccessor(getValueAccessor(key));\n                        };\n                        allBindings['has'] = function(key) {\n                            return key in bindings;\n                        };\n\n                        if (ko.bindingEvent.childrenComplete in bindings) {\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.childrenComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.childrenComplete]);\n                                if (callback) {\n                                    var nodes = ko.virtualElements.childNodes(node);\n                                    if (nodes.length) {\n                                        callback(nodes, ko.dataFor(nodes[0]));\n                                    }\n                                }\n                            });\n                        }\n\n                        if (ko.bindingEvent.descendantsComplete in bindings) {\n                            contextToExtend = ko.bindingEvent.startPossiblyAsyncContentBinding(node, bindingContext);\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.descendantsComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.descendantsComplete]);\n                                if (callback && ko.virtualElements.firstChild(node)) {\n                                    callback(node);\n                                }\n                            });\n                        }\n\n                        // First put the bindings into the right order\n                        var orderedBindings = topologicalSortBindings(bindings);\n\n                        // Go through the sorted bindings, calling init and update for each\n                        ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {\n                            // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,\n                            // so bindingKeyAndHandler.handler will always be nonnull.\n                            var handlerInitFn = bindingKeyAndHandler.handler[\"init\"],\n                                handlerUpdateFn = bindingKeyAndHandler.handler[\"update\"],\n                                bindingKey = bindingKeyAndHandler.key;\n\n                            if (node.nodeType === 8) {\n                                validateThatBindingIsAllowedForVirtualElements(bindingKey);\n                            }\n\n                            try {\n                                // Run init, ignoring any dependencies\n                                if (typeof handlerInitFn == \"function\") {\n                                    ko.dependencyDetection.ignore(function() {\n                                        var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n\n                                        // If this binding handler claims to control descendant bindings, make a note of this\n                                        if (initResult && initResult['controlsDescendantBindings']) {\n                                            if (bindingHandlerThatControlsDescendantBindings !== undefined)\n                                                throw new Error(\"Multiple bindings (\" + bindingHandlerThatControlsDescendantBindings + \" and \" + bindingKey + \") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.\");\n                                            bindingHandlerThatControlsDescendantBindings = bindingKey;\n                                        }\n                                    });\n                                }\n\n                                // Run update in its own computed wrapper\n                                if (typeof handlerUpdateFn == \"function\") {\n                                    ko.dependentObservable(\n                                        function() {\n                                            handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n                                        },\n                                        null,\n                                        { disposeWhenNodeIsRemoved: node }\n                                    );\n                                }\n                            } catch (ex) {\n                                ex.message = \"Unable to process binding \\\"\" + bindingKey + \": \" + bindings[bindingKey] + \"\\\"\\nMessage: \" + ex.message;\n                                throw ex;\n                            }\n                        });\n                    }\n\n                    var shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined;\n                    return {\n                        'shouldBindDescendants': shouldBindDescendants,\n                        'bindingContextForDescendants': shouldBindDescendants && contextToExtend\n                    };\n                };\n\n                ko.storedBindingContextForNode = function (node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                    return bindingInfo && bindingInfo.context;\n                }\n\n                function getBindingContext(viewModelOrBindingContext, extendContextCallback) {\n                    return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)\n                        ? viewModelOrBindingContext\n                        : new ko.bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback);\n                }\n\n                ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(node);\n                    return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));\n                };\n\n                ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    var context = getBindingContext(viewModelOrBindingContext);\n                    return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);\n                };\n\n                ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {\n                    if (rootNode.nodeType === 1 || rootNode.nodeType === 8)\n                        applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);\n                };\n\n                ko.applyBindings = function (viewModelOrBindingContext, rootNode, extendContextCallback) {\n                    // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.\n                    if (!jQueryInstance && window['jQuery']) {\n                        jQueryInstance = window['jQuery'];\n                    }\n\n                    if (arguments.length < 2) {\n                        rootNode = document.body;\n                        if (!rootNode) {\n                            throw Error(\"ko.applyBindings: could not find document.body; has the document been loaded?\");\n                        }\n                    } else if (!rootNode || (rootNode.nodeType !== 1 && rootNode.nodeType !== 8)) {\n                        throw Error(\"ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node\");\n                    }\n\n                    applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext, extendContextCallback), rootNode);\n                };\n\n                // Retrieving binding context from arbitrary nodes\n                ko.contextFor = function(node) {\n                    // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)\n                    if (node && (node.nodeType === 1 || node.nodeType === 8)) {\n                        return ko.storedBindingContextForNode(node);\n                    }\n                    return undefined;\n                };\n                ko.dataFor = function(node) {\n                    var context = ko.contextFor(node);\n                    return context ? context['$data'] : undefined;\n                };\n\n                ko.exportSymbol('bindingHandlers', ko.bindingHandlers);\n                ko.exportSymbol('bindingEvent', ko.bindingEvent);\n                ko.exportSymbol('bindingEvent.subscribe', ko.bindingEvent.subscribe);\n                ko.exportSymbol('bindingEvent.startPossiblyAsyncContentBinding', ko.bindingEvent.startPossiblyAsyncContentBinding);\n                ko.exportSymbol('applyBindings', ko.applyBindings);\n                ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);\n                ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);\n                ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);\n                ko.exportSymbol('contextFor', ko.contextFor);\n                ko.exportSymbol('dataFor', ko.dataFor);\n            })();\n            (function(undefined) {\n                var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight\n                    loadedDefinitionsCache = {};    // Tracks component loads that have already completed\n\n                ko.components = {\n                    get: function(componentName, callback) {\n                        var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);\n                        if (cachedDefinition) {\n                            // It's already loaded and cached. Reuse the same definition object.\n                            // Note that for API consistency, even cache hits complete asynchronously by default.\n                            // You can bypass this by putting synchronous:true on your component config.\n                            if (cachedDefinition.isSynchronousComponent) {\n                                ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning\n                                    callback(cachedDefinition.definition);\n                                });\n                            } else {\n                                ko.tasks.schedule(function() { callback(cachedDefinition.definition); });\n                            }\n                        } else {\n                            // Join the loading process that is already underway, or start a new one.\n                            loadComponentAndNotify(componentName, callback);\n                        }\n                    },\n\n                    clearCachedDefinition: function(componentName) {\n                        delete loadedDefinitionsCache[componentName];\n                    },\n\n                    _getFirstResultFromLoaders: getFirstResultFromLoaders\n                };\n\n                function getObjectOwnProperty(obj, propName) {\n                    return Object.prototype.hasOwnProperty.call(obj, propName) ? obj[propName] : undefined;\n                }\n\n                function loadComponentAndNotify(componentName, callback) {\n                    var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),\n                        completedAsync;\n                    if (!subscribable) {\n                        // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.\n                        subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();\n                        subscribable.subscribe(callback);\n\n                        beginLoadingComponent(componentName, function(definition, config) {\n                            var isSynchronousComponent = !!(config && config['synchronous']);\n                            loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };\n                            delete loadingSubscribablesCache[componentName];\n\n                            // For API consistency, all loads complete asynchronously. However we want to avoid\n                            // adding an extra task schedule if it's unnecessary (i.e., the completion is already\n                            // async).\n                            //\n                            // You can bypass the 'always asynchronous' feature by putting the synchronous:true\n                            // flag on your component configuration when you register it.\n                            if (completedAsync || isSynchronousComponent) {\n                                // Note that notifySubscribers ignores any dependencies read within the callback.\n                                // See comment in loaderRegistryBehaviors.js for reasoning\n                                subscribable['notifySubscribers'](definition);\n                            } else {\n                                ko.tasks.schedule(function() {\n                                    subscribable['notifySubscribers'](definition);\n                                });\n                            }\n                        });\n                        completedAsync = true;\n                    } else {\n                        subscribable.subscribe(callback);\n                    }\n                }\n\n                function beginLoadingComponent(componentName, callback) {\n                    getFirstResultFromLoaders('getConfig', [componentName], function(config) {\n                        if (config) {\n                            // We have a config, so now load its definition\n                            getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {\n                                callback(definition, config);\n                            });\n                        } else {\n                            // The component has no config - it's unknown to all the loaders.\n                            // Note that this is not an error (e.g., a module loading error) - that would abort the\n                            // process and this callback would not run. For this callback to run, all loaders must\n                            // have confirmed they don't know about this component.\n                            callback(null, null);\n                        }\n                    });\n                }\n\n                function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {\n                    // On the first call in the stack, start with the full set of loaders\n                    if (!candidateLoaders) {\n                        candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array\n                    }\n\n                    // Try the next candidate\n                    var currentCandidateLoader = candidateLoaders.shift();\n                    if (currentCandidateLoader) {\n                        var methodInstance = currentCandidateLoader[methodName];\n                        if (methodInstance) {\n                            var wasAborted = false,\n                                synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {\n                                    if (wasAborted) {\n                                        callback(null);\n                                    } else if (result !== null) {\n                                        // This candidate returned a value. Use it.\n                                        callback(result);\n                                    } else {\n                                        // Try the next candidate\n                                        getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                                    }\n                                }));\n\n                            // Currently, loaders may not return anything synchronously. This leaves open the possibility\n                            // that we'll extend the API to support synchronous return values in the future. It won't be\n                            // a breaking change, because currently no loader is allowed to return anything except undefined.\n                            if (synchronousReturnValue !== undefined) {\n                                wasAborted = true;\n\n                                // Method to suppress exceptions will remain undocumented. This is only to keep\n                                // KO's specs running tidily, since we can observe the loading got aborted without\n                                // having exceptions cluttering up the console too.\n                                if (!currentCandidateLoader['suppressLoaderExceptions']) {\n                                    throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');\n                                }\n                            }\n                        } else {\n                            // This candidate doesn't have the relevant handler. Synchronously move on to the next one.\n                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                        }\n                    } else {\n                        // No candidates returned a value\n                        callback(null);\n                    }\n                }\n\n                // Reference the loaders via string name so it's possible for developers\n                // to replace the whole array by assigning to ko.components.loaders\n                ko.components['loaders'] = [];\n\n                ko.exportSymbol('components', ko.components);\n                ko.exportSymbol('components.get', ko.components.get);\n                ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);\n            })();\n            (function(undefined) {\n\n                // The default loader is responsible for two things:\n                // 1. Maintaining the default in-memory registry of component configuration objects\n                //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))\n                // 2. Answering requests for components by fetching configuration objects\n                //    from that default in-memory registry and resolving them into standard\n                //    component definition objects (of the form { createViewModel: ..., template: ... })\n                // Custom loaders may override either of these facilities, i.e.,\n                // 1. To supply configuration objects from some other source (e.g., conventions)\n                // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.\n\n                var defaultConfigRegistry = {};\n\n                ko.components.register = function(componentName, config) {\n                    if (!config) {\n                        throw new Error('Invalid configuration for ' + componentName);\n                    }\n\n                    if (ko.components.isRegistered(componentName)) {\n                        throw new Error('Component ' + componentName + ' is already registered');\n                    }\n\n                    defaultConfigRegistry[componentName] = config;\n                };\n\n                ko.components.isRegistered = function(componentName) {\n                    return Object.prototype.hasOwnProperty.call(defaultConfigRegistry, componentName);\n                };\n\n                ko.components.unregister = function(componentName) {\n                    delete defaultConfigRegistry[componentName];\n                    ko.components.clearCachedDefinition(componentName);\n                };\n\n                ko.components.defaultLoader = {\n                    'getConfig': function(componentName, callback) {\n                        var result = ko.components.isRegistered(componentName)\n                            ? defaultConfigRegistry[componentName]\n                            : null;\n                        callback(result);\n                    },\n\n                    'loadComponent': function(componentName, config, callback) {\n                        var errorCallback = makeErrorCallback(componentName);\n                        possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {\n                            resolveConfig(componentName, errorCallback, loadedConfig, callback);\n                        });\n                    },\n\n                    'loadTemplate': function(componentName, templateConfig, callback) {\n                        resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);\n                    },\n\n                    'loadViewModel': function(componentName, viewModelConfig, callback) {\n                        resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);\n                    }\n                };\n\n                var createViewModelKey = 'createViewModel';\n\n                // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it\n                // into the standard component definition format:\n                //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.\n                // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed\n                // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,\n                // so this is implemented manually below.\n                function resolveConfig(componentName, errorCallback, config, callback) {\n                    var result = {},\n                        makeCallBackWhenZero = 2,\n                        tryIssueCallback = function() {\n                            if (--makeCallBackWhenZero === 0) {\n                                callback(result);\n                            }\n                        },\n                        templateConfig = config['template'],\n                        viewModelConfig = config['viewModel'];\n\n                    if (templateConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {\n                                result['template'] = resolvedTemplate;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n\n                    if (viewModelConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {\n                                result[createViewModelKey] = resolvedViewModel;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n                }\n\n                function resolveTemplate(errorCallback, templateConfig, callback) {\n                    if (typeof templateConfig === 'string') {\n                        // Markup - parse it\n                        callback(ko.utils.parseHtmlFragment(templateConfig));\n                    } else if (templateConfig instanceof Array) {\n                        // Assume already an array of DOM nodes - pass through unchanged\n                        callback(templateConfig);\n                    } else if (isDocumentFragment(templateConfig)) {\n                        // Document fragment - use its child nodes\n                        callback(ko.utils.makeArray(templateConfig.childNodes));\n                    } else if (templateConfig['element']) {\n                        var element = templateConfig['element'];\n                        if (isDomElement(element)) {\n                            // Element instance - copy its child nodes\n                            callback(cloneNodesFromTemplateSourceElement(element));\n                        } else if (typeof element === 'string') {\n                            // Element ID - find it, then copy its child nodes\n                            var elemInstance = document.getElementById(element);\n                            if (elemInstance) {\n                                callback(cloneNodesFromTemplateSourceElement(elemInstance));\n                            } else {\n                                errorCallback('Cannot find element with ID ' + element);\n                            }\n                        } else {\n                            errorCallback('Unknown element type: ' + element);\n                        }\n                    } else {\n                        errorCallback('Unknown template value: ' + templateConfig);\n                    }\n                }\n\n                function resolveViewModel(errorCallback, viewModelConfig, callback) {\n                    if (typeof viewModelConfig === 'function') {\n                        // Constructor - convert to standard factory function format\n                        // By design, this does *not* supply componentInfo to the constructor, as the intent is that\n                        // componentInfo contains non-viewmodel data (e.g., the component's element) that should only\n                        // be used in factory functions, not viewmodel constructors.\n                        callback(function (params /*, componentInfo */) {\n                            return new viewModelConfig(params);\n                        });\n                    } else if (typeof viewModelConfig[createViewModelKey] === 'function') {\n                        // Already a factory function - use it as-is\n                        callback(viewModelConfig[createViewModelKey]);\n                    } else if ('instance' in viewModelConfig) {\n                        // Fixed object instance - promote to createViewModel format for API consistency\n                        var fixedInstance = viewModelConfig['instance'];\n                        callback(function (params, componentInfo) {\n                            return fixedInstance;\n                        });\n                    } else if ('viewModel' in viewModelConfig) {\n                        // Resolved AMD module whose value is of the form { viewModel: ... }\n                        resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);\n                    } else {\n                        errorCallback('Unknown viewModel value: ' + viewModelConfig);\n                    }\n                }\n\n                function cloneNodesFromTemplateSourceElement(elemInstance) {\n                    switch (ko.utils.tagNameLower(elemInstance)) {\n                        case 'script':\n                            return ko.utils.parseHtmlFragment(elemInstance.text);\n                        case 'textarea':\n                            return ko.utils.parseHtmlFragment(elemInstance.value);\n                        case 'template':\n                            // For browsers with proper <template> element support (i.e., where the .content property\n                            // gives a document fragment), use that document fragment.\n                            if (isDocumentFragment(elemInstance.content)) {\n                                return ko.utils.cloneNodes(elemInstance.content.childNodes);\n                            }\n                    }\n\n                    // Regular elements such as <div>, and <template> elements on old browsers that don't really\n                    // understand <template> and just treat it as a regular container\n                    return ko.utils.cloneNodes(elemInstance.childNodes);\n                }\n\n                function isDomElement(obj) {\n                    if (window['HTMLElement']) {\n                        return obj instanceof HTMLElement;\n                    } else {\n                        return obj && obj.tagName && obj.nodeType === 1;\n                    }\n                }\n\n                function isDocumentFragment(obj) {\n                    if (window['DocumentFragment']) {\n                        return obj instanceof DocumentFragment;\n                    } else {\n                        return obj && obj.nodeType === 11;\n                    }\n                }\n\n                function possiblyGetConfigFromAmd(errorCallback, config, callback) {\n                    if (typeof config['require'] === 'string') {\n                        // The config is the value of an AMD module\n                        if (amdRequire || window['require']) {\n                            (amdRequire || window['require'])([config['require']], function (module) {\n                                if (module && typeof module === 'object' && module.__esModule && module.default) {\n                                    module = module.default;\n                                }\n                                callback(module);\n                            });\n                        } else {\n                            errorCallback('Uses require, but no AMD loader is present');\n                        }\n                    } else {\n                        callback(config);\n                    }\n                }\n\n                function makeErrorCallback(componentName) {\n                    return function (message) {\n                        throw new Error('Component \\'' + componentName + '\\': ' + message);\n                    };\n                }\n\n                ko.exportSymbol('components.register', ko.components.register);\n                ko.exportSymbol('components.isRegistered', ko.components.isRegistered);\n                ko.exportSymbol('components.unregister', ko.components.unregister);\n\n                // Expose the default loader so that developers can directly ask it for configuration\n                // or to resolve configuration\n                ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);\n\n                // By default, the default loader is the only registered component loader\n                ko.components['loaders'].push(ko.components.defaultLoader);\n\n                // Privately expose the underlying config registry for use in old-IE shim\n                ko.components._allRegisteredComponents = defaultConfigRegistry;\n            })();\n            (function (undefined) {\n                // Overridable API for determining which component name applies to a given node. By overriding this,\n                // you can for example map specific tagNames to components that are not preregistered.\n                ko.components['getComponentNameForNode'] = function(node) {\n                    var tagNameLower = ko.utils.tagNameLower(node);\n                    if (ko.components.isRegistered(tagNameLower)) {\n                        // Try to determine that this node can be considered a *custom* element; see https://github.com/knockout/knockout/issues/1603\n                        if (tagNameLower.indexOf('-') != -1 || ('' + node) == \"[object HTMLUnknownElement]\" || (ko.utils.ieVersion <= 8 && node.tagName === tagNameLower)) {\n                            return tagNameLower;\n                        }\n                    }\n                };\n\n                ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {\n                    // Determine if it's really a custom element matching a component\n                    if (node.nodeType === 1) {\n                        var componentName = ko.components['getComponentNameForNode'](node);\n                        if (componentName) {\n                            // It does represent a component, so add a component binding for it\n                            allBindings = allBindings || {};\n\n                            if (allBindings['component']) {\n                                // Avoid silently overwriting some other 'component' binding that may already be on the element\n                                throw new Error('Cannot use the \"component\" binding on a custom element matching a component');\n                            }\n\n                            var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };\n\n                            allBindings['component'] = valueAccessors\n                                ? function() { return componentBindingValue; }\n                                : componentBindingValue;\n                        }\n                    }\n\n                    return allBindings;\n                }\n\n                var nativeBindingProviderInstance = new ko.bindingProvider();\n\n                function getComponentParamsFromCustomElement(elem, bindingContext) {\n                    var paramsAttribute = elem.getAttribute('params');\n\n                    if (paramsAttribute) {\n                        var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),\n                            rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {\n                                return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });\n                            }),\n                            result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {\n                                var paramValue = paramValueComputed.peek();\n                                // Does the evaluation of the parameter value unwrap any observables?\n                                if (!paramValueComputed.isActive()) {\n                                    // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.\n                                    // Example: \"someVal: firstName, age: 123\" (whether or not firstName is an observable/computed)\n                                    return paramValue;\n                                } else {\n                                    // Yes it does. Supply a computed property that unwraps both the outer (binding expression)\n                                    // level of observability, and any inner (resulting model value) level of observability.\n                                    // This means the component doesn't have to worry about multiple unwrapping. If the value is a\n                                    // writable observable, the computed will also be writable and pass the value on to the observable.\n                                    return ko.computed({\n                                        'read': function() {\n                                            return ko.utils.unwrapObservable(paramValueComputed());\n                                        },\n                                        'write': ko.isWriteableObservable(paramValue) && function(value) {\n                                            paramValueComputed()(value);\n                                        },\n                                        disposeWhenNodeIsRemoved: elem\n                                    });\n                                }\n                            });\n\n                        // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'\n                        // This is in case the developer wants to react to outer (binding) observability separately from inner\n                        // (model value) observability, or in case the model value observable has subobservables.\n                        if (!Object.prototype.hasOwnProperty.call(result, '$raw')) {\n                            result['$raw'] = rawParamComputedValues;\n                        }\n\n                        return result;\n                    } else {\n                        // For consistency, absence of a \"params\" attribute is treated the same as the presence of\n                        // any empty one. Otherwise component viewmodels need special code to check whether or not\n                        // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.\n                        return { '$raw': {} };\n                    }\n                }\n\n                // --------------------------------------------------------------------------------\n                // Compatibility code for older (pre-HTML5) IE browsers\n\n                if (ko.utils.ieVersion < 9) {\n                    // Whenever you preregister a component, enable it as a custom element in the current document\n                    ko.components['register'] = (function(originalFunction) {\n                        return function(componentName) {\n                            document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element\n                            return originalFunction.apply(this, arguments);\n                        }\n                    })(ko.components['register']);\n\n                    // Whenever you create a document fragment, enable all preregistered component names as custom elements\n                    // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements\n                    document.createDocumentFragment = (function(originalFunction) {\n                        return function() {\n                            var newDocFrag = originalFunction(),\n                                allComponents = ko.components._allRegisteredComponents;\n                            for (var componentName in allComponents) {\n                                if (Object.prototype.hasOwnProperty.call(allComponents, componentName)) {\n                                    newDocFrag.createElement(componentName);\n                                }\n                            }\n                            return newDocFrag;\n                        };\n                    })(document.createDocumentFragment);\n                }\n            })();(function(undefined) {\n                var componentLoadingOperationUniqueId = 0;\n\n                ko.bindingHandlers['component'] = {\n                    'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {\n                        var currentViewModel,\n                            currentLoadingOperationId,\n                            afterRenderSub,\n                            disposeAssociatedComponentViewModel = function () {\n                                var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];\n                                if (typeof currentViewModelDispose === 'function') {\n                                    currentViewModelDispose.call(currentViewModel);\n                                }\n                                if (afterRenderSub) {\n                                    afterRenderSub.dispose();\n                                }\n                                afterRenderSub = null;\n                                currentViewModel = null;\n                                // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion\n                                currentLoadingOperationId = null;\n                            },\n                            originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));\n\n                        ko.virtualElements.emptyNode(element);\n                        ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);\n\n                        ko.computed(function () {\n                            var value = ko.utils.unwrapObservable(valueAccessor()),\n                                componentName, componentParams;\n\n                            if (typeof value === 'string') {\n                                componentName = value;\n                            } else {\n                                componentName = ko.utils.unwrapObservable(value['name']);\n                                componentParams = ko.utils.unwrapObservable(value['params']);\n                            }\n\n                            if (!componentName) {\n                                throw new Error('No component name specified');\n                            }\n\n                            var asyncContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n\n                            var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;\n                            ko.components.get(componentName, function(componentDefinition) {\n                                // If this is not the current load operation for this element, ignore it.\n                                if (currentLoadingOperationId !== loadingOperationId) {\n                                    return;\n                                }\n\n                                // Clean up previous state\n                                disposeAssociatedComponentViewModel();\n\n                                // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.\n                                if (!componentDefinition) {\n                                    throw new Error('Unknown component \\'' + componentName + '\\'');\n                                }\n                                cloneTemplateIntoElement(componentName, componentDefinition, element);\n\n                                var componentInfo = {\n                                    'element': element,\n                                    'templateNodes': originalChildNodes\n                                };\n\n                                var componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo),\n                                    childBindingContext = asyncContext['createChildContext'](componentViewModel, {\n                                        'extend': function(ctx) {\n                                            ctx['$component'] = componentViewModel;\n                                            ctx['$componentTemplateNodes'] = originalChildNodes;\n                                        }\n                                    });\n\n                                if (componentViewModel && componentViewModel['koDescendantsComplete']) {\n                                    afterRenderSub = ko.bindingEvent.subscribe(element, ko.bindingEvent.descendantsComplete, componentViewModel['koDescendantsComplete'], componentViewModel);\n                                }\n\n                                currentViewModel = componentViewModel;\n                                ko.applyBindingsToDescendants(childBindingContext, element);\n                            });\n                        }, null, { disposeWhenNodeIsRemoved: element });\n\n                        return { 'controlsDescendantBindings': true };\n                    }\n                };\n\n                ko.virtualElements.allowedBindings['component'] = true;\n\n                function cloneTemplateIntoElement(componentName, componentDefinition, element) {\n                    var template = componentDefinition['template'];\n                    if (!template) {\n                        throw new Error('Component \\'' + componentName + '\\' has no template');\n                    }\n\n                    var clonedNodesArray = ko.utils.cloneNodes(template);\n                    ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);\n                }\n\n                function createViewModel(componentDefinition, componentParams, componentInfo) {\n                    var componentViewModelFactory = componentDefinition['createViewModel'];\n                    return componentViewModelFactory\n                        ? componentViewModelFactory.call(componentDefinition, componentParams, componentInfo)\n                        : componentParams; // Template-only component\n                }\n\n            })();\n            var attrHtmlToJavaScriptMap = { 'class': 'className', 'for': 'htmlFor' };\n            ko.bindingHandlers['attr'] = {\n                'update': function(element, valueAccessor, allBindings) {\n                    var value = ko.utils.unwrapObservable(valueAccessor()) || {};\n                    ko.utils.objectForEach(value, function(attrName, attrValue) {\n                        attrValue = ko.utils.unwrapObservable(attrValue);\n\n                        // Find the namespace of this attribute, if any.\n                        var prefixLen = attrName.indexOf(':');\n                        var namespace = \"lookupNamespaceURI\" in element && prefixLen > 0 && element.lookupNamespaceURI(attrName.substr(0, prefixLen));\n\n                        // To cover cases like \"attr: { checked:someProp }\", we want to remove the attribute entirely\n                        // when someProp is a \"no value\"-like value (strictly null, false, or undefined)\n                        // (because the absence of the \"checked\" attr is how to mark an element as not checked, etc.)\n                        var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);\n                        if (toRemove) {\n                            namespace ? element.removeAttributeNS(namespace, attrName) : element.removeAttribute(attrName);\n                        } else {\n                            attrValue = attrValue.toString();\n                        }\n\n                        // In IE <= 7 and IE8 Quirks Mode, you have to use the JavaScript property name instead of the\n                        // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,\n                        // but instead of figuring out the mode, we'll just set the attribute through the JavaScript\n                        // property for IE <= 8.\n                        if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavaScriptMap) {\n                            attrName = attrHtmlToJavaScriptMap[attrName];\n                            if (toRemove)\n                                element.removeAttribute(attrName);\n                            else\n                                element[attrName] = attrValue;\n                        } else if (!toRemove) {\n                            namespace ? element.setAttributeNS(namespace, attrName, attrValue) : element.setAttribute(attrName, attrValue);\n                        }\n\n                        // Treat \"name\" specially - although you can think of it as an attribute, it also needs\n                        // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)\n                        // Deliberately being case-sensitive here because XHTML would regard \"Name\" as a different thing\n                        // entirely, and there's no strong reason to allow for such casing in HTML.\n                        if (attrName === \"name\") {\n                            ko.utils.setElementName(element, toRemove ? \"\" : attrValue);\n                        }\n                    });\n                }\n            };\n            (function() {\n\n                ko.bindingHandlers['checked'] = {\n                    'after': ['value', 'attr'],\n                    'init': function (element, valueAccessor, allBindings) {\n                        var checkedValue = ko.pureComputed(function() {\n                            // Treat \"value\" like \"checkedValue\" when it is included with \"checked\" binding\n                            if (allBindings['has']('checkedValue')) {\n                                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n                            } else if (useElementValue) {\n                                if (allBindings['has']('value')) {\n                                    return ko.utils.unwrapObservable(allBindings.get('value'));\n                                } else {\n                                    return element.value;\n                                }\n                            }\n                        });\n\n                        function updateModel() {\n                            // This updates the model value from the view value.\n                            // It runs in response to DOM events (click) and changes in checkedValue.\n                            var isChecked = element.checked,\n                                elemValue = checkedValue();\n\n                            // When we're first setting up this computed, don't change any model state.\n                            if (ko.computedContext.isInitial()) {\n                                return;\n                            }\n\n                            // We can ignore unchecked radio buttons, because some other radio\n                            // button will be checked, and that one can take care of updating state.\n                            // Also ignore value changes to an already unchecked checkbox.\n                            if (!isChecked && (isRadio || ko.computedContext.getDependenciesCount())) {\n                                return;\n                            }\n\n                            var modelValue = ko.dependencyDetection.ignore(valueAccessor);\n                            if (valueIsArray) {\n                                var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue,\n                                    saveOldValue = oldElemValue;\n                                oldElemValue = elemValue;\n\n                                if (saveOldValue !== elemValue) {\n                                    // When we're responding to the checkedValue changing, and the element is\n                                    // currently checked, replace the old elem value with the new elem value\n                                    // in the model array.\n                                    if (isChecked) {\n                                        ko.utils.addOrRemoveItem(writableValue, elemValue, true);\n                                        ko.utils.addOrRemoveItem(writableValue, saveOldValue, false);\n                                    }\n                                } else {\n                                    // When we're responding to the user having checked/unchecked a checkbox,\n                                    // add/remove the element value to the model array.\n                                    ko.utils.addOrRemoveItem(writableValue, elemValue, isChecked);\n                                }\n\n                                if (rawValueIsNonArrayObservable && ko.isWriteableObservable(modelValue)) {\n                                    modelValue(writableValue);\n                                }\n                            } else {\n                                if (isCheckbox) {\n                                    if (elemValue === undefined) {\n                                        elemValue = isChecked;\n                                    } else if (!isChecked) {\n                                        elemValue = undefined;\n                                    }\n                                }\n                                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n                            }\n                        };\n\n                        function updateView() {\n                            // This updates the view value from the model value.\n                            // It runs in response to changes in the bound (checked) value.\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor()),\n                                elemValue = checkedValue();\n\n                            if (valueIsArray) {\n                                // When a checkbox is bound to an array, being checked represents its value being present in that array\n                                element.checked = ko.utils.arrayIndexOf(modelValue, elemValue) >= 0;\n                                oldElemValue = elemValue;\n                            } else if (isCheckbox && elemValue === undefined) {\n                                // When a checkbox is bound to any other value (not an array) and \"checkedValue\" is not defined,\n                                // being checked represents the value being trueish\n                                element.checked = !!modelValue;\n                            } else {\n                                // Otherwise, being checked means that the checkbox or radio button's value corresponds to the model value\n                                element.checked = (checkedValue() === modelValue);\n                            }\n                        };\n\n                        var isCheckbox = element.type == \"checkbox\",\n                            isRadio = element.type == \"radio\";\n\n                        // Only bind to check boxes and radio buttons\n                        if (!isCheckbox && !isRadio) {\n                            return;\n                        }\n\n                        var rawValue = valueAccessor(),\n                            valueIsArray = isCheckbox && (ko.utils.unwrapObservable(rawValue) instanceof Array),\n                            rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice),\n                            useElementValue = isRadio || valueIsArray,\n                            oldElemValue = valueIsArray ? checkedValue() : undefined;\n\n                        // IE 6 won't allow radio buttons to be selected unless they have a name\n                        if (isRadio && !element.name)\n                            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });\n\n                        // Set up two computeds to update the binding:\n\n                        // The first responds to changes in the checkedValue value and to element clicks\n                        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });\n                        ko.utils.registerEventHandler(element, \"click\", updateModel);\n\n                        // The second responds to changes in the model value (the one associated with the checked binding)\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n\n                        rawValue = undefined;\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['checked'] = true;\n\n                ko.bindingHandlers['checkedValue'] = {\n                    'update': function (element, valueAccessor) {\n                        element.value = ko.utils.unwrapObservable(valueAccessor());\n                    }\n                };\n\n            })();var classesWrittenByBindingKey = '__ko__cssValue';\n            ko.bindingHandlers['class'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.stringTrim(ko.utils.unwrapObservable(valueAccessor()));\n                    ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);\n                    element[classesWrittenByBindingKey] = value;\n                    ko.utils.toggleDomNodeCssClass(element, value, true);\n                }\n            };\n\n            ko.bindingHandlers['css'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value !== null && typeof value == \"object\") {\n                        ko.utils.objectForEach(value, function(className, shouldHaveClass) {\n                            shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);\n                            ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);\n                        });\n                    } else {\n                        ko.bindingHandlers['class']['update'](element, valueAccessor);\n                    }\n                }\n            };\n            ko.bindingHandlers['enable'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value && element.disabled)\n                        element.removeAttribute(\"disabled\");\n                    else if ((!value) && (!element.disabled))\n                        element.disabled = true;\n                }\n            };\n\n            ko.bindingHandlers['disable'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// For certain common events (currently just 'click'), allow a simplified data-binding syntax\n// e.g. click:handler instead of the usual full-length event:{click:handler}\n            function makeEventHandlerShortcut(eventName) {\n                ko.bindingHandlers[eventName] = {\n                    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var newValueAccessor = function () {\n                            var result = {};\n                            result[eventName] = valueAccessor();\n                            return result;\n                        };\n                        return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);\n                    }\n                }\n            }\n\n            ko.bindingHandlers['event'] = {\n                'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var eventsToHandle = valueAccessor() || {};\n                    ko.utils.objectForEach(eventsToHandle, function(eventName) {\n                        if (typeof eventName == \"string\") {\n                            ko.utils.registerEventHandler(element, eventName, function (event) {\n                                var handlerReturnValue;\n                                var handlerFunction = valueAccessor()[eventName];\n                                if (!handlerFunction)\n                                    return;\n\n                                try {\n                                    // Take all the event args, and prefix with the viewmodel\n                                    var argsForHandler = ko.utils.makeArray(arguments);\n                                    viewModel = bindingContext['$data'];\n                                    argsForHandler.unshift(viewModel);\n                                    handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);\n                                } finally {\n                                    if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                        if (event.preventDefault)\n                                            event.preventDefault();\n                                        else\n                                            event.returnValue = false;\n                                    }\n                                }\n\n                                var bubble = allBindings.get(eventName + 'Bubble') !== false;\n                                if (!bubble) {\n                                    event.cancelBubble = true;\n                                    if (event.stopPropagation)\n                                        event.stopPropagation();\n                                }\n                            });\n                        }\n                    });\n                }\n            };\n// \"foreach: someExpression\" is equivalent to \"template: { foreach: someExpression }\"\n// \"foreach: { data: someExpression, afterAdd: myfn }\" is equivalent to \"template: { foreach: someExpression, afterAdd: myfn }\"\n            ko.bindingHandlers['foreach'] = {\n                makeTemplateValueAccessor: function(valueAccessor) {\n                    return function() {\n                        var modelValue = valueAccessor(),\n                            unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here\n\n                        // If unwrappedValue is the array, pass in the wrapped value on its own\n                        // The value will be unwrapped and tracked within the template binding\n                        // (See https://github.com/SteveSanderson/knockout/issues/523)\n                        if ((!unwrappedValue) || typeof unwrappedValue.length == \"number\")\n                            return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };\n\n                        // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates\n                        ko.utils.unwrapObservable(modelValue);\n                        return {\n                            'foreach': unwrappedValue['data'],\n                            'as': unwrappedValue['as'],\n                            'noChildContext': unwrappedValue['noChildContext'],\n                            'includeDestroyed': unwrappedValue['includeDestroyed'],\n                            'afterAdd': unwrappedValue['afterAdd'],\n                            'beforeRemove': unwrappedValue['beforeRemove'],\n                            'afterRender': unwrappedValue['afterRender'],\n                            'beforeMove': unwrappedValue['beforeMove'],\n                            'afterMove': unwrappedValue['afterMove'],\n                            'templateEngine': ko.nativeTemplateEngine.instance\n                        };\n                    };\n                },\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));\n                },\n                'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);\n                }\n            };\n            ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings\n            ko.virtualElements.allowedBindings['foreach'] = true;\n            var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';\n            var hasfocusLastValue = '__ko_hasfocusLastValue';\n            ko.bindingHandlers['hasfocus'] = {\n                'init': function(element, valueAccessor, allBindings) {\n                    var handleElementFocusChange = function(isFocused) {\n                        // Where possible, ignore which event was raised and determine focus state using activeElement,\n                        // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.\n                        // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,\n                        // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus\n                        // from calling 'blur()' on the element when it loses focus.\n                        // Discussion at https://github.com/SteveSanderson/knockout/pull/352\n                        element[hasfocusUpdatingProperty] = true;\n                        var ownerDoc = element.ownerDocument;\n                        if (\"activeElement\" in ownerDoc) {\n                            var active;\n                            try {\n                                active = ownerDoc.activeElement;\n                            } catch(e) {\n                                // IE9 throws if you access activeElement during page load (see issue #703)\n                                active = ownerDoc.body;\n                            }\n                            isFocused = (active === element);\n                        }\n                        var modelValue = valueAccessor();\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);\n\n                        //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function\n                        element[hasfocusLastValue] = isFocused;\n                        element[hasfocusUpdatingProperty] = false;\n                    };\n                    var handleElementFocusIn = handleElementFocusChange.bind(null, true);\n                    var handleElementFocusOut = handleElementFocusChange.bind(null, false);\n\n                    ko.utils.registerEventHandler(element, \"focus\", handleElementFocusIn);\n                    ko.utils.registerEventHandler(element, \"focusin\", handleElementFocusIn); // For IE\n                    ko.utils.registerEventHandler(element, \"blur\",  handleElementFocusOut);\n                    ko.utils.registerEventHandler(element, \"focusout\",  handleElementFocusOut); // For IE\n\n                    // Assume element is not focused (prevents \"blur\" being called initially)\n                    element[hasfocusLastValue] = false;\n                },\n                'update': function(element, valueAccessor) {\n                    var value = !!ko.utils.unwrapObservable(valueAccessor());\n\n                    if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {\n                        value ? element.focus() : element.blur();\n\n                        // In IE, the blur method doesn't always cause the element to lose focus (for example, if the window is not in focus).\n                        // Setting focus to the body element does seem to be reliable in IE, but should only be used if we know that the current\n                        // element was focused already.\n                        if (!value && element[hasfocusLastValue]) {\n                            element.ownerDocument.body.focus();\n                        }\n\n                        // For IE, which doesn't reliably fire \"focus\" or \"blur\" events synchronously\n                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? \"focusin\" : \"focusout\"]);\n                    }\n                }\n            };\n            ko.expressionRewriting.twoWayBindings['hasfocus'] = true;\n\n            ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make \"hasFocus\" an alias\n            ko.expressionRewriting.twoWayBindings['hasFocus'] = 'hasfocus';\n            ko.bindingHandlers['html'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    // setHtml will unwrap the value if needed\n                    ko.utils.setHtml(element, valueAccessor());\n                }\n            };\n            (function () {\n\n// Makes a binding like with or if\n                function makeWithIfBinding(bindingKey, isWith, isNot) {\n                    ko.bindingHandlers[bindingKey] = {\n                        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                            var didDisplayOnLastUpdate, savedNodes, contextOptions = {}, completeOnRender, needAsyncContext, renderOnEveryChange;\n\n                            if (isWith) {\n                                var as = allBindings.get('as'), noChildContext = allBindings.get('noChildContext');\n                                renderOnEveryChange = !(as && noChildContext);\n                                contextOptions = { 'as': as, 'noChildContext': noChildContext, 'exportDependencies': renderOnEveryChange };\n                            }\n\n                            completeOnRender = allBindings.get(\"completeOn\") == \"render\";\n                            needAsyncContext = completeOnRender || allBindings['has'](ko.bindingEvent.descendantsComplete);\n\n                            ko.computed(function() {\n                                var value = ko.utils.unwrapObservable(valueAccessor()),\n                                    shouldDisplay = !isNot !== !value, // equivalent to isNot ? !value : !!value,\n                                    isInitial = !savedNodes,\n                                    childContext;\n\n                                if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {\n                                    return;\n                                }\n\n                                if (needAsyncContext) {\n                                    bindingContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isWith || renderOnEveryChange) {\n                                        contextOptions['dataDependency'] = ko.computedContext.computed();\n                                    }\n\n                                    if (isWith) {\n                                        childContext = bindingContext['createChildContext'](typeof value == \"function\" ? value : valueAccessor, contextOptions);\n                                    } else if (ko.computedContext.getDependenciesCount()) {\n                                        childContext = bindingContext['extend'](null, contextOptions);\n                                    } else {\n                                        childContext = bindingContext;\n                                    }\n                                }\n\n                                // Save a copy of the inner nodes on the initial update, but only if we have dependencies.\n                                if (isInitial && ko.computedContext.getDependenciesCount()) {\n                                    savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isInitial) {\n                                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));\n                                    }\n\n                                    ko.applyBindingsToDescendants(childContext, element);\n                                } else {\n                                    ko.virtualElements.emptyNode(element);\n\n                                    if (!completeOnRender) {\n                                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                                    }\n                                }\n\n                                didDisplayOnLastUpdate = shouldDisplay;\n\n                            }, null, { disposeWhenNodeIsRemoved: element });\n\n                            return { 'controlsDescendantBindings': true };\n                        }\n                    };\n                    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings\n                    ko.virtualElements.allowedBindings[bindingKey] = true;\n                }\n\n// Construct the actual binding handlers\n                makeWithIfBinding('if');\n                makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);\n                makeWithIfBinding('with', true /* isWith */);\n\n            })();ko.bindingHandlers['let'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    // Make a modified binding context, with extra properties, and apply it to descendant elements\n                    var innerContext = bindingContext['extend'](valueAccessor);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['let'] = true;\n            var captionPlaceholder = {};\n            ko.bindingHandlers['options'] = {\n                'init': function(element) {\n                    if (ko.utils.tagNameLower(element) !== \"select\")\n                        throw new Error(\"options binding applies only to SELECT elements\");\n\n                    // Remove all existing <option>s.\n                    while (element.length > 0) {\n                        element.remove(0);\n                    }\n\n                    // Ensures that the binding processor doesn't try to bind the options\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor, allBindings) {\n                    function selectedOptions() {\n                        return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });\n                    }\n\n                    var selectWasPreviouslyEmpty = element.length == 0,\n                        multiple = element.multiple,\n                        previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,\n                        unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n                        valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),\n                        includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n                        arrayToDomNodeChildrenOptions = {},\n                        captionValue,\n                        filteredArray,\n                        previousSelectedValues = [];\n\n                    if (!valueAllowUnset) {\n                        if (multiple) {\n                            previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);\n                        } else if (element.selectedIndex >= 0) {\n                            previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));\n                        }\n                    }\n\n                    if (unwrappedArray) {\n                        if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                            unwrappedArray = [unwrappedArray];\n\n                        // Filter out any entries marked as destroyed\n                        filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                            return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                        });\n\n                        // If caption is included, add it to the array\n                        if (allBindings['has']('optionsCaption')) {\n                            captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));\n                            // If caption value is null or undefined, don't show a caption\n                            if (captionValue !== null && captionValue !== undefined) {\n                                filteredArray.unshift(captionPlaceholder);\n                            }\n                        }\n                    } else {\n                        // If a falsy value is provided (e.g. null), we'll simply empty the select element\n                    }\n\n                    function applyToObject(object, predicate, defaultValue) {\n                        var predicateType = typeof predicate;\n                        if (predicateType == \"function\")    // Given a function; run it against the data value\n                            return predicate(object);\n                        else if (predicateType == \"string\") // Given a string; treat it as a property name on the data value\n                            return object[predicate];\n                        else                                // Given no optionsText arg; use the data value itself\n                            return defaultValue;\n                    }\n\n                    // The following functions can run at two different times:\n                    // The first is when the whole array is being updated directly from this binding handler.\n                    // The second is when an observable value for a specific array entry is updated.\n                    // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.\n                    var itemUpdate = false;\n                    function optionForArrayItem(arrayEntry, index, oldOptions) {\n                        if (oldOptions.length) {\n                            previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];\n                            itemUpdate = true;\n                        }\n                        var option = element.ownerDocument.createElement(\"option\");\n                        if (arrayEntry === captionPlaceholder) {\n                            ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n                            ko.selectExtensions.writeValue(option, undefined);\n                        } else {\n                            // Apply a value to the option element\n                            var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);\n                            ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));\n\n                            // Apply some text to the option element\n                            var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);\n                            ko.utils.setTextContent(option, optionText);\n                        }\n                        return [option];\n                    }\n\n                    // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection\n                    // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208\n                    arrayToDomNodeChildrenOptions['beforeRemove'] =\n                        function (option) {\n                            element.removeChild(option);\n                        };\n\n                    function setSelectionCallback(arrayEntry, newOptions) {\n                        if (itemUpdate && valueAllowUnset) {\n                            // The model value is authoritative, so make sure its value is the one selected\n                            ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                        } else if (previousSelectedValues.length) {\n                            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.\n                            // That's why we first added them without selection. Now it's time to set the selection.\n                            var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;\n                            ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);\n\n                            // If this option was changed from being selected during a single-item update, notify the change\n                            if (itemUpdate && !isSelected) {\n                                ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                            }\n                        }\n                    }\n\n                    var callback = setSelectionCallback;\n                    if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == \"function\") {\n                        callback = function(arrayEntry, newOptions) {\n                            setSelectionCallback(arrayEntry, newOptions);\n                            ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);\n                        }\n                    }\n\n                    ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);\n\n                    if (!valueAllowUnset) {\n                        // Determine if the selection has changed as a result of updating the options list\n                        var selectionChanged;\n                        if (multiple) {\n                            // For a multiple-select box, compare the new selection count to the previous one\n                            // But if nothing was selected before, the selection can't have changed\n                            selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;\n                        } else {\n                            // For a single-select box, compare the current value to the previous value\n                            // But if nothing was selected before or nothing is selected now, just look for a change in selection\n                            selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)\n                                ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])\n                                : (previousSelectedValues.length || element.selectedIndex >= 0);\n                        }\n\n                        // Ensure consistency between model value and selected option.\n                        // If the dropdown was changed so that selection is no longer the same,\n                        // notify the value or selectedOptions binding.\n                        if (selectionChanged) {\n                            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                        }\n                    }\n\n                    if (valueAllowUnset || ko.computedContext.isInitial()) {\n                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                    }\n\n                    // Workaround for IE bug\n                    ko.utils.ensureSelectElementIsRenderedCorrectly(element);\n\n                    if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)\n                        element.scrollTop = previousScrollTop;\n                }\n            };\n            ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();\n            ko.bindingHandlers['selectedOptions'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    function updateFromView() {\n                        var value = valueAccessor(), valueToWrite = [];\n                        ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                            if (node.selected)\n                                valueToWrite.push(ko.selectExtensions.readValue(node));\n                        });\n                        ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);\n                    }\n\n                    function updateFromModel() {\n                        var newValue = ko.utils.unwrapObservable(valueAccessor()),\n                            previousScrollTop = element.scrollTop;\n\n                        if (newValue && typeof newValue.length == \"number\") {\n                            ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;\n                                if (node.selected != isSelected) {      // This check prevents flashing of the select element in IE\n                                    ko.utils.setOptionNodeSelectionState(node, isSelected);\n                                }\n                            });\n                        }\n\n                        element.scrollTop = previousScrollTop;\n                    }\n\n                    if (ko.utils.tagNameLower(element) != \"select\") {\n                        throw new Error(\"selectedOptions binding applies only to SELECT elements\");\n                    }\n\n                    var updateFromModelComputed;\n                    ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                        if (!updateFromModelComputed) {\n                            ko.utils.registerEventHandler(element, \"change\", updateFromView);\n                            updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                        } else {\n                            updateFromView();\n                        }\n                    }, null, { 'notifyImmediately': true });\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped binding\n            };\n            ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;\n            ko.bindingHandlers['style'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor() || {});\n                    ko.utils.objectForEach(value, function(styleName, styleValue) {\n                        styleValue = ko.utils.unwrapObservable(styleValue);\n\n                        if (styleValue === null || styleValue === undefined || styleValue === false) {\n                            // Empty string removes the value, whereas null/undefined have no effect\n                            styleValue = \"\";\n                        }\n\n                        if (jQueryInstance) {\n                            jQueryInstance(element)['css'](styleName, styleValue);\n                        } else if (/^--/.test(styleName)) {\n                            // Is styleName a custom CSS property?\n                            element.style.setProperty(styleName, styleValue);\n                        } else {\n                            styleName = styleName.replace(/-(\\w)/g, function (all, letter) {\n                                return letter.toUpperCase();\n                            });\n\n                            var previousStyle = element.style[styleName];\n                            element.style[styleName] = styleValue;\n\n                            if (styleValue !== previousStyle && element.style[styleName] == previousStyle && !isNaN(styleValue)) {\n                                element.style[styleName] = styleValue + \"px\";\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['submit'] = {\n                'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    if (typeof valueAccessor() != \"function\")\n                        throw new Error(\"The value for a submit binding must be a function\");\n                    ko.utils.registerEventHandler(element, \"submit\", function (event) {\n                        var handlerReturnValue;\n                        var value = valueAccessor();\n                        try { handlerReturnValue = value.call(bindingContext['$data'], element); }\n                        finally {\n                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                if (event.preventDefault)\n                                    event.preventDefault();\n                                else\n                                    event.returnValue = false;\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['text'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).\n                    // It should also make things faster, as we no longer have to consider whether the text node might be bindable.\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    ko.utils.setTextContent(element, valueAccessor());\n                }\n            };\n            ko.virtualElements.allowedBindings['text'] = true;\n            (function () {\n\n                if (window && window.navigator) {\n                    var parseVersion = function (matches) {\n                        if (matches) {\n                            return parseFloat(matches[1]);\n                        }\n                    };\n\n                    // Detect various browser versions because some old versions don't fully support the 'input' event\n                    var userAgent = window.navigator.userAgent,\n                        operaVersion, chromeVersion, safariVersion, firefoxVersion, ieVersion, edgeVersion;\n\n                    (operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()))\n                    || (edgeVersion = parseVersion(userAgent.match(/Edge\\/([^ ]+)$/)))\n                    || (chromeVersion = parseVersion(userAgent.match(/Chrome\\/([^ ]+)/)))\n                    || (safariVersion = parseVersion(userAgent.match(/Version\\/([^ ]+) Safari/)))\n                    || (firefoxVersion = parseVersion(userAgent.match(/Firefox\\/([^ ]+)/)))\n                    || (ieVersion = ko.utils.ieVersion || parseVersion(userAgent.match(/MSIE ([^ ]+)/)))      // Detects up to IE 10\n                    || (ieVersion = parseVersion(userAgent.match(/rv:([^ )]+)/)));      // Detects IE 11\n                }\n\n// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.\n// But it does fire the 'selectionchange' event on many of those, presumably because the\n// cursor is moving and that counts as the selection changing. The 'selectionchange' event is\n// fired at the document level only and doesn't directly indicate which element changed. We\n// set up just one event handler for the document and use 'activeElement' to determine which\n// element was changed.\n                if (ieVersion >= 8 && ieVersion < 10) {\n                    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),\n                        selectionChangeHandlerName = ko.utils.domData.nextKey();\n                    var selectionChangeHandler = function(event) {\n                        var target = this.activeElement,\n                            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);\n                        if (handler) {\n                            handler(event);\n                        }\n                    };\n                    var registerForSelectionChangeEvent = function (element, handler) {\n                        var ownerDoc = element.ownerDocument;\n                        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {\n                            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);\n                            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);\n                        }\n                        ko.utils.domData.set(element, selectionChangeHandlerName, handler);\n                    };\n                }\n\n                ko.bindingHandlers['textInput'] = {\n                    'init': function (element, valueAccessor, allBindings) {\n\n                        var previousElementValue = element.value,\n                            timeoutHandle,\n                            elementValueBeforeEvent;\n\n                        var updateModel = function (event) {\n                            clearTimeout(timeoutHandle);\n                            elementValueBeforeEvent = timeoutHandle = undefined;\n\n                            var elementValue = element.value;\n                            if (previousElementValue !== elementValue) {\n                                // Provide a way for tests to know exactly which event was processed\n                                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;\n                                previousElementValue = elementValue;\n                                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);\n                            }\n                        };\n\n                        var deferUpdateModel = function (event) {\n                            if (!timeoutHandle) {\n                                // The elementValueBeforeEvent variable is set *only* during the brief gap between an\n                                // event firing and the updateModel function running. This allows us to ignore model\n                                // updates that are from the previous state of the element, usually due to techniques\n                                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.\n                                elementValueBeforeEvent = element.value;\n                                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;\n                                timeoutHandle = ko.utils.setTimeout(handler, 4);\n                            }\n                        };\n\n                        // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);\n                        // so we'll make sure all updates are asynchronous\n                        var ieUpdateModel = ko.utils.ieVersion == 9 ? deferUpdateModel : updateModel,\n                            ourUpdate = false;\n\n                        var updateView = function () {\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                            if (modelValue === null || modelValue === undefined) {\n                                modelValue = '';\n                            }\n\n                            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateView, 4);\n                                return;\n                            }\n\n                            // Update the element only if the element and model are different. On some browsers, updating the value\n                            // will move the cursor to the end of the input, which would be bad while the user is typing.\n                            if (element.value !== modelValue) {\n                                ourUpdate = true;  // Make sure we ignore events (propertychange) that result from updating the value\n                                element.value = modelValue;\n                                ourUpdate = false;\n                                previousElementValue = element.value; // In case the browser changes the value (see #2281)\n                            }\n                        };\n\n                        var onEvent = function (event, handler) {\n                            ko.utils.registerEventHandler(element, event, handler);\n                        };\n\n                        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {\n                            // Provide a way for tests to specify exactly which events are bound\n                            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {\n                                if (eventName.slice(0,5) == 'after') {\n                                    onEvent(eventName.slice(5), deferUpdateModel);\n                                } else {\n                                    onEvent(eventName, updateModel);\n                                }\n                            });\n                        } else {\n                            if (ieVersion) {\n                                // All versions (including 11) of Internet Explorer have a bug that they don't generate an input or propertychange event when ESC is pressed\n                                onEvent('keypress', updateModel);\n                            }\n                            if (ieVersion < 11) {\n                                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever\n                                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,\n                                // but that's an acceptable compromise for this binding. IE 9 and 10 support 'input', but since they don't always\n                                // fire it when using autocomplete, we'll use 'propertychange' for them also.\n                                onEvent('propertychange', function(event) {\n                                    if (!ourUpdate && event.propertyName === 'value') {\n                                        ieUpdateModel(event);\n                                    }\n                                });\n                            }\n                            if (ieVersion == 8) {\n                                // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from\n                                // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following\n                                // events too.\n                                onEvent('keyup', updateModel);      // A single keystoke\n                                onEvent('keydown', updateModel);    // The first character when a key is held down\n                            }\n                            if (registerForSelectionChangeEvent) {\n                                // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using\n                                // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text\n                                // out of the field, and cutting or deleting text using the context menu. 'selectionchange'\n                                // can detect all of those except dragging text out of the field, for which we use 'dragend'.\n                                // These are also needed in IE8 because of the bug described above.\n                                registerForSelectionChangeEvent(element, ieUpdateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.\n                                onEvent('dragend', deferUpdateModel);\n                            }\n\n                            if (!ieVersion || ieVersion >= 9) {\n                                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed\n                                // through the user interface.\n                                onEvent('input', ieUpdateModel);\n                            }\n\n                            if (safariVersion < 5 && ko.utils.tagNameLower(element) === \"textarea\") {\n                                // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'\n                                // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.\n                                onEvent('keydown', deferUpdateModel);\n                                onEvent('paste', deferUpdateModel);\n                                onEvent('cut', deferUpdateModel);\n                            } else if (operaVersion < 11) {\n                                // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.\n                                // We can try to catch some of those using 'keydown'.\n                                onEvent('keydown', deferUpdateModel);\n                            } else if (firefoxVersion < 4.0) {\n                                // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete\n                                onEvent('DOMAutoComplete', updateModel);\n\n                                // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.\n                                onEvent('dragdrop', updateModel);       // <3.5\n                                onEvent('drop', updateModel);           // 3.5\n                            } else if (edgeVersion && element.type === \"number\") {\n                                // Microsoft Edge doesn't fire 'input' or 'change' events for number inputs when\n                                // the value is changed via the up / down arrow keys\n                                onEvent('keydown', deferUpdateModel);\n                            }\n                        }\n\n                        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.\n                        onEvent('change', updateModel);\n\n                        // To deal with browsers that don't notify any kind of event for some changes (IE, Safari, etc.)\n                        onEvent('blur', updateModel);\n\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['textInput'] = true;\n\n// textinput is an alias for textInput\n                ko.bindingHandlers['textinput'] = {\n                    // preprocess is the only way to set up a full alias\n                    'preprocess': function (value, name, addBinding) {\n                        addBinding('textInput', value);\n                    }\n                };\n\n            })();ko.bindingHandlers['uniqueName'] = {\n                'init': function (element, valueAccessor) {\n                    if (valueAccessor()) {\n                        var name = \"ko_unique_\" + (++ko.bindingHandlers['uniqueName'].currentIndex);\n                        ko.utils.setElementName(element, name);\n                    }\n                }\n            };\n            ko.bindingHandlers['uniqueName'].currentIndex = 0;\n            ko.bindingHandlers['using'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var options;\n\n                    if (allBindings['has']('as')) {\n                        options = { 'as': allBindings.get('as'), 'noChildContext': allBindings.get('noChildContext') };\n                    }\n\n                    var innerContext = bindingContext['createChildContext'](valueAccessor, options);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['using'] = true;\n            ko.bindingHandlers['value'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    var tagName = ko.utils.tagNameLower(element),\n                        isInputElement = tagName == \"input\";\n\n                    // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit\n                    if (isInputElement && (element.type == \"checkbox\" || element.type == \"radio\")) {\n                        ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });\n                        return;\n                    }\n\n                    var eventsToCatch = [];\n                    var requestedEventsToCatch = allBindings.get(\"valueUpdate\");\n                    var propertyChangedFired = false;\n                    var elementValueBeforeEvent = null;\n\n                    if (requestedEventsToCatch) {\n                        // Allow both individual event names, and arrays of event names\n                        if (typeof requestedEventsToCatch == \"string\") {\n                            eventsToCatch = [requestedEventsToCatch];\n                        } else {\n                            eventsToCatch = ko.utils.arrayGetDistinctValues(requestedEventsToCatch);\n                        }\n                        ko.utils.arrayRemoveItem(eventsToCatch, \"change\");  // We'll subscribe to \"change\" events later\n                    }\n\n                    var valueUpdateHandler = function() {\n                        elementValueBeforeEvent = null;\n                        propertyChangedFired = false;\n                        var modelValue = valueAccessor();\n                        var elementValue = ko.selectExtensions.readValue(element);\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);\n                    }\n\n                    // Workaround for https://github.com/SteveSanderson/knockout/issues/122\n                    // IE doesn't fire \"change\" events on textboxes if the user selects a value from its autocomplete list\n                    var ieAutoCompleteHackNeeded = ko.utils.ieVersion && isInputElement && element.type == \"text\"\n                        && element.autocomplete != \"off\" && (!element.form || element.form.autocomplete != \"off\");\n                    if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, \"propertychange\") == -1) {\n                        ko.utils.registerEventHandler(element, \"propertychange\", function () { propertyChangedFired = true });\n                        ko.utils.registerEventHandler(element, \"focus\", function () { propertyChangedFired = false });\n                        ko.utils.registerEventHandler(element, \"blur\", function() {\n                            if (propertyChangedFired) {\n                                valueUpdateHandler();\n                            }\n                        });\n                    }\n\n                    ko.utils.arrayForEach(eventsToCatch, function(eventName) {\n                        // The syntax \"after<eventname>\" means \"run the handler asynchronously after the event\"\n                        // This is useful, for example, to catch \"keydown\" events after the browser has updated the control\n                        // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)\n                        var handler = valueUpdateHandler;\n                        if (ko.utils.stringStartsWith(eventName, \"after\")) {\n                            handler = function() {\n                                // The elementValueBeforeEvent variable is non-null *only* during the brief gap between\n                                // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen\n                                // at the earliest asynchronous opportunity. We store this temporary information so that\n                                // if, between keyX and valueUpdateHandler, the underlying model value changes separately,\n                                // we can overwrite that model value change with the value the user just typed. Otherwise,\n                                // techniques like rateLimit can trigger model changes at critical moments that will\n                                // override the user's inputs, causing keystrokes to be lost.\n                                elementValueBeforeEvent = ko.selectExtensions.readValue(element);\n                                ko.utils.setTimeout(valueUpdateHandler, 0);\n                            };\n                            eventName = eventName.substring(\"after\".length);\n                        }\n                        ko.utils.registerEventHandler(element, eventName, handler);\n                    });\n\n                    var updateFromModel;\n\n                    if (isInputElement && element.type == \"file\") {\n                        // For file input elements, can only write the empty string\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            if (newValue === null || newValue === undefined || newValue === \"\") {\n                                element.value = \"\";\n                            } else {\n                                ko.dependencyDetection.ignore(valueUpdateHandler);  // reset the model to match the element\n                            }\n                        }\n                    } else {\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            var elementValue = ko.selectExtensions.readValue(element);\n\n                            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateFromModel, 0);\n                                return;\n                            }\n\n                            var valueHasChanged = newValue !== elementValue;\n\n                            if (valueHasChanged || elementValue === undefined) {\n                                if (tagName === \"select\") {\n                                    var allowUnset = allBindings.get('valueAllowUnset');\n                                    ko.selectExtensions.writeValue(element, newValue, allowUnset);\n                                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {\n                                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,\n                                        // because you're not allowed to have a model value that disagrees with a visible UI selection.\n                                        ko.dependencyDetection.ignore(valueUpdateHandler);\n                                    }\n                                } else {\n                                    ko.selectExtensions.writeValue(element, newValue);\n                                }\n                            }\n                        };\n                    }\n\n                    if (tagName === \"select\") {\n                        var updateFromModelComputed;\n                        ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                            if (!updateFromModelComputed) {\n                                ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                                updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                            } else if (allBindings.get('valueAllowUnset')) {\n                                updateFromModel();\n                            } else {\n                                valueUpdateHandler();\n                            }\n                        }, null, { 'notifyImmediately': true });\n                    } else {\n                        ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding\n            };\n            ko.expressionRewriting.twoWayBindings['value'] = true;\n            ko.bindingHandlers['visible'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    var isCurrentlyVisible = !(element.style.display == \"none\");\n                    if (value && !isCurrentlyVisible)\n                        element.style.display = \"\";\n                    else if ((!value) && isCurrentlyVisible)\n                        element.style.display = \"none\";\n                }\n            };\n\n            ko.bindingHandlers['hidden'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['visible']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// 'click' is just a shorthand for the usual full-length event:{click:handler}\n            makeEventHandlerShortcut('click');\n// If you want to make a custom template engine,\n//\n// [1] Inherit from this class (like ko.nativeTemplateEngine does)\n// [2] Override 'renderTemplateSource', supplying a function with this signature:\n//\n//        function (templateSource, bindingContext, options) {\n//            // - templateSource.text() is the text of the template you should render\n//            // - bindingContext.$data is the data you should pass into the template\n//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,\n//            //     and bindingContext.$root available in the template too\n//            // - options gives you access to any other properties set on \"data-bind: { template: options }\"\n//            // - templateDocument is the document object of the template\n//            //\n//            // Return value: an array of DOM nodes\n//        }\n//\n// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:\n//\n//        function (script) {\n//            // Return value: Whatever syntax means \"Evaluate the JavaScript statement 'script' and output the result\"\n//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'\n//        }\n//\n//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.\n//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)\n//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.\n\n            ko.templateEngine = function () { };\n\n            ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                throw new Error(\"Override renderTemplateSource\");\n            };\n\n            ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {\n                throw new Error(\"Override createJavaScriptEvaluatorBlock\");\n            };\n\n            ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {\n                // Named template\n                if (typeof template == \"string\") {\n                    templateDocument = templateDocument || document;\n                    var elem = templateDocument.getElementById(template);\n                    if (!elem)\n                        throw new Error(\"Cannot find template with ID \" + template);\n                    return new ko.templateSources.domElement(elem);\n                } else if ((template.nodeType == 1) || (template.nodeType == 8)) {\n                    // Anonymous template\n                    return new ko.templateSources.anonymousTemplate(template);\n                } else\n                    throw new Error(\"Unknown template type: \" + template);\n            };\n\n            ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);\n            };\n\n            ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {\n                // Skip rewriting if requested\n                if (this['allowTemplateRewriting'] === false)\n                    return true;\n                return this['makeTemplateSource'](template, templateDocument)['data'](\"isRewritten\");\n            };\n\n            ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                var rewritten = rewriterCallback(templateSource['text']());\n                templateSource['text'](rewritten);\n                templateSource['data'](\"isRewritten\", true);\n            };\n\n            ko.exportSymbol('templateEngine', ko.templateEngine);\n\n            ko.templateRewriting = (function () {\n                var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\\d*)(?:\\s+(?!data-bind\\s*=\\s*)[a-z0-9\\-]+(?:=(?:\\\"[^\\\"]*\\\"|\\'[^\\']*\\'|[^>]*))?)*\\s+)data-bind\\s*=\\s*([\"'])([\\s\\S]*?)\\3/gi;\n                var memoizeVirtualContainerBindingSyntaxRegex = /<!--\\s*ko\\b\\s*([\\s\\S]*?)\\s*-->/g;\n\n                function validateDataBindValuesForRewriting(keyValueArray) {\n                    var allValidators = ko.expressionRewriting.bindingRewriteValidators;\n                    for (var i = 0; i < keyValueArray.length; i++) {\n                        var key = keyValueArray[i]['key'];\n                        if (Object.prototype.hasOwnProperty.call(allValidators, key)) {\n                            var validator = allValidators[key];\n\n                            if (typeof validator === \"function\") {\n                                var possibleErrorMessage = validator(keyValueArray[i]['value']);\n                                if (possibleErrorMessage)\n                                    throw new Error(possibleErrorMessage);\n                            } else if (!validator) {\n                                throw new Error(\"This template engine does not support the '\" + key + \"' binding within its templates\");\n                            }\n                        }\n                    }\n                }\n\n                function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {\n                    var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);\n                    validateDataBindValuesForRewriting(dataBindKeyValueArray);\n                    var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});\n\n                    // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional\n                    // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this\n                    // extra indirection.\n                    var applyBindingsToNextSiblingScript =\n                        \"ko.__tr_ambtns(function($context,$element){return(function(){return{ \" + rewrittenDataBindAttributeValue + \" } })()},'\" + nodeName.toLowerCase() + \"')\";\n                    return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;\n                }\n\n                return {\n                    ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {\n                        if (!templateEngine['isTemplateRewritten'](template, templateDocument))\n                            templateEngine['rewriteTemplate'](template, function (htmlString) {\n                                return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);\n                            }, templateDocument);\n                    },\n\n                    memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {\n                        return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);\n                        }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ \"<!-- ko -->\", /* nodeName: */ \"#comment\", templateEngine);\n                        });\n                    },\n\n                    applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {\n                        return ko.memoization.memoize(function (domNode, bindingContext) {\n                            var nodeToBind = domNode.nextSibling;\n                            if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {\n                                ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);\n                            }\n                        });\n                    }\n                }\n            })();\n\n\n// Exported only because it has to be referenced by string lookup from within rewritten template\n            ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);\n            (function() {\n                // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving\n                // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)\n                //\n                // Two are provided by default:\n                //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element\n                //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but\n                //                                           without reading/writing the actual element text content, since it will be overwritten\n                //                                           with the rendered template output.\n                // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.\n                // Template sources need to have the following functions:\n                //   text() \t\t\t- returns the template text from your storage location\n                //   text(value)\t\t- writes the supplied template text to your storage location\n                //   data(key)\t\t\t- reads values stored using data(key, value) - see below\n                //   data(key, value)\t- associates \"value\" with this template and the key \"key\". Is used to store information like \"isRewritten\".\n                //\n                // Optionally, template sources can also have the following functions:\n                //   nodes()            - returns a DOM element containing the nodes of this template, where available\n                //   nodes(value)       - writes the given DOM element to your storage location\n                // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()\n                // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().\n                //\n                // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were\n                // using and overriding \"makeTemplateSource\" to return an instance of your custom template source.\n\n                ko.templateSources = {};\n\n                // ---- ko.templateSources.domElement -----\n\n                // template types\n                var templateScript = 1,\n                    templateTextArea = 2,\n                    templateTemplate = 3,\n                    templateElement = 4;\n\n                ko.templateSources.domElement = function(element) {\n                    this.domElement = element;\n\n                    if (element) {\n                        var tagNameLower = ko.utils.tagNameLower(element);\n                        this.templateType =\n                            tagNameLower === \"script\" ? templateScript :\n                                tagNameLower === \"textarea\" ? templateTextArea :\n                                    // For browsers with proper <template> element support, where the .content property gives a document fragment\n                                    tagNameLower == \"template\" && element.content && element.content.nodeType === 11 ? templateTemplate :\n                                        templateElement;\n                    }\n                }\n\n                ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {\n                    var elemContentsProperty = this.templateType === templateScript ? \"text\"\n                        : this.templateType === templateTextArea ? \"value\"\n                            : \"innerHTML\";\n\n                    if (arguments.length == 0) {\n                        return this.domElement[elemContentsProperty];\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (elemContentsProperty === \"innerHTML\")\n                            ko.utils.setHtml(this.domElement, valueToWrite);\n                        else\n                            this.domElement[elemContentsProperty] = valueToWrite;\n                    }\n                };\n\n                var dataDomDataPrefix = ko.utils.domData.nextKey() + \"_\";\n                ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {\n                    if (arguments.length === 1) {\n                        return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);\n                    } else {\n                        ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);\n                    }\n                };\n\n                var templatesDomDataKey = ko.utils.domData.nextKey();\n                function getTemplateDomData(element) {\n                    return ko.utils.domData.get(element, templatesDomDataKey) || {};\n                }\n                function setTemplateDomData(element, data) {\n                    ko.utils.domData.set(element, templatesDomDataKey, data);\n                }\n\n                ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {\n                    var element = this.domElement;\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(element),\n                            nodes = templateData.containerData || (\n                                this.templateType === templateTemplate ? element.content :\n                                    this.templateType === templateElement ? element :\n                                        undefined);\n                        if (!nodes || templateData.alwaysCheckText) {\n                            // If the template is associated with an element that stores the template as text,\n                            // parse and cache the nodes whenever there's new text content available. This allows\n                            // the user to update the template content by updating the text of template node.\n                            var text = this['text']();\n                            if (text && text !== templateData.textData) {\n                                nodes = ko.utils.parseHtmlForTemplateNodes(text, element.ownerDocument);\n                                setTemplateDomData(element, {containerData: nodes, textData: text, alwaysCheckText: true});\n                            }\n                        }\n                        return nodes;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (this.templateType !== undefined) {\n                            this['text'](\"\");   // clear the text from the node\n                        }\n                        setTemplateDomData(element, {containerData: valueToWrite});\n                    }\n                };\n\n                // ---- ko.templateSources.anonymousTemplate -----\n                // Anonymous templates are normally saved/retrieved as DOM nodes through \"nodes\".\n                // For compatibility, you can also read \"text\"; it will be serialized from the nodes on demand.\n                // Writing to \"text\" is still supported, but then the template data will not be available as DOM nodes.\n\n                ko.templateSources.anonymousTemplate = function(element) {\n                    this.domElement = element;\n                }\n                ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();\n                ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;\n                ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(this.domElement);\n                        if (templateData.textData === undefined && templateData.containerData)\n                            templateData.textData = templateData.containerData.innerHTML;\n                        return templateData.textData;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        setTemplateDomData(this.domElement, {textData: valueToWrite});\n                    }\n                };\n\n                ko.exportSymbol('templateSources', ko.templateSources);\n                ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);\n                ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);\n            })();\n            (function () {\n                var _templateEngine;\n                ko.setTemplateEngine = function (templateEngine) {\n                    if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))\n                        throw new Error(\"templateEngine must inherit from ko.templateEngine\");\n                    _templateEngine = templateEngine;\n                }\n\n                function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {\n                    var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);\n                    while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {\n                        nextInQueue = ko.virtualElements.nextSibling(node);\n                        action(node, nextInQueue);\n                    }\n                }\n\n                function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {\n                    // To be used on any nodes that have been rendered by a template and have been inserted into some parent element\n                    // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because\n                    // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,\n                    // (1) Does a regular \"applyBindings\" to associate bindingContext with this node and to activate any non-memoized bindings\n                    // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)\n\n                    if (continuousNodeArray.length) {\n                        var firstNode = continuousNodeArray[0],\n                            lastNode = continuousNodeArray[continuousNodeArray.length - 1],\n                            parentNode = firstNode.parentNode,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        if (preprocessNode) {\n                            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {\n                                var nodePreviousSibling = node.previousSibling;\n                                var newNodes = preprocessNode.call(provider, node);\n                                if (newNodes) {\n                                    if (node === firstNode)\n                                        firstNode = newNodes[0] || nextNodeInRange;\n                                    if (node === lastNode)\n                                        lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;\n                                }\n                            });\n\n                            // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.\n                            // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real\n                            // first node needs to be in the array).\n                            continuousNodeArray.length = 0;\n                            if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do\n                                return;\n                            }\n                            if (firstNode === lastNode) {\n                                continuousNodeArray.push(firstNode);\n                            } else {\n                                continuousNodeArray.push(firstNode, lastNode);\n                                ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                            }\n                        }\n\n                        // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)\n                        // whereas a regular applyBindings won't introduce new memoized nodes\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.applyBindings(bindingContext, node);\n                        });\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);\n                        });\n\n                        // Make sure any changes done by applyBindings or unmemoize are reflected in the array\n                        ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                    }\n                }\n\n                function getFirstNodeFromPossibleArray(nodeOrNodeArray) {\n                    return nodeOrNodeArray.nodeType ? nodeOrNodeArray\n                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]\n                            : null;\n                }\n\n                function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {\n                    options = options || {};\n                    var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                    var templateDocument = (firstTargetNode || template || {}).ownerDocument;\n                    var templateEngineToUse = (options['templateEngine'] || _templateEngine);\n                    ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);\n                    var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);\n\n                    // Loosely check result is an array of DOM nodes\n                    if ((typeof renderedNodesArray.length != \"number\") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != \"number\"))\n                        throw new Error(\"Template engine must return an array of DOM nodes\");\n\n                    var haveAddedNodesToParent = false;\n                    switch (renderMode) {\n                        case \"replaceChildren\":\n                            ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"replaceNode\":\n                            ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"ignoreTargetNode\": break;\n                        default:\n                            throw new Error(\"Unknown renderMode: \" + renderMode);\n                    }\n\n                    if (haveAddedNodesToParent) {\n                        activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);\n                        if (options['afterRender']) {\n                            ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext[options['as'] || '$data']]);\n                        }\n                        if (renderMode == \"replaceChildren\") {\n                            ko.bindingEvent.notify(targetNodeOrNodeArray, ko.bindingEvent.childrenComplete);\n                        }\n                    }\n\n                    return renderedNodesArray;\n                }\n\n                function resolveTemplateName(template, data, context) {\n                    // The template can be specified as:\n                    if (ko.isObservable(template)) {\n                        // 1. An observable, with string value\n                        return template();\n                    } else if (typeof template === 'function') {\n                        // 2. A function of (data, context) returning a string\n                        return template(data, context);\n                    } else {\n                        // 3. A string\n                        return template;\n                    }\n                }\n\n                ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {\n                    options = options || {};\n                    if ((options['templateEngine'] || _templateEngine) == undefined)\n                        throw new Error(\"Set a template engine before calling renderTemplate\");\n                    renderMode = renderMode || \"replaceChildren\";\n\n                    if (targetNodeOrNodeArray) {\n                        var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n\n                        var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)\n                        var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == \"replaceNode\") ? firstTargetNode.parentNode : firstTargetNode;\n\n                        return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes\n                            function () {\n                                // Ensure we've got a proper binding context to work with\n                                var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))\n                                    ? dataOrBindingContext\n                                    : new ko.bindingContext(dataOrBindingContext, null, null, null, { \"exportDependencies\": true });\n\n                                var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),\n                                    renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);\n\n                                if (renderMode == \"replaceNode\") {\n                                    targetNodeOrNodeArray = renderedNodesArray;\n                                    firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                                }\n                            },\n                            null,\n                            { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }\n                        );\n                    } else {\n                        // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node\n                        return ko.memoization.memoize(function (domNode) {\n                            ko.renderTemplate(template, dataOrBindingContext, options, domNode, \"replaceNode\");\n                        });\n                    }\n                };\n\n                ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {\n                    // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then\n                    // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.\n                    var arrayItemContext, asName = options['as'];\n\n                    // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode\n                    var executeTemplateForArrayItem = function (arrayValue, index) {\n                        // Support selecting template as a function of the data being rendered\n                        arrayItemContext = parentBindingContext['createChildContext'](arrayValue, {\n                            'as': asName,\n                            'noChildContext': options['noChildContext'],\n                            'extend': function(context) {\n                                context['$index'] = index;\n                                if (asName) {\n                                    context[asName + \"Index\"] = index;\n                                }\n                            }\n                        });\n\n                        var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);\n                        return executeTemplate(targetNode, \"ignoreTargetNode\", templateName, arrayItemContext, options);\n                    };\n\n                    // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode\n                    var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {\n                        activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);\n                        if (options['afterRender'])\n                            options['afterRender'](addedNodesArray, arrayValue);\n\n                        // release the \"cache\" variable, so that it can be collected by\n                        // the GC when its value isn't used from within the bindings anymore.\n                        arrayItemContext = null;\n                    };\n\n                    var setDomNodeChildrenFromArrayMapping = function (newArray, changeList) {\n                        // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).\n                        // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.\n                        ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, newArray, executeTemplateForArrayItem, options, activateBindingsCallback, changeList]);\n                        ko.bindingEvent.notify(targetNode, ko.bindingEvent.childrenComplete);\n                    };\n\n                    var shouldHideDestroyed = (options['includeDestroyed'] === false) || (ko.options['foreachHidesDestroyed'] && !options['includeDestroyed']);\n\n                    if (!shouldHideDestroyed && !options['beforeRemove'] && ko.isObservableArray(arrayOrObservableArray)) {\n                        setDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek());\n\n                        var subscription = arrayOrObservableArray.subscribe(function (changeList) {\n                            setDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList);\n                        }, null, \"arrayChange\");\n                        subscription.disposeWhenNodeIsRemoved(targetNode);\n\n                        return subscription;\n                    } else {\n                        return ko.dependentObservable(function () {\n                            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];\n                            if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                                unwrappedArray = [unwrappedArray];\n\n                            if (shouldHideDestroyed) {\n                                // Filter out any entries marked as destroyed\n                                unwrappedArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                                    return item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                                });\n                            }\n                            setDomNodeChildrenFromArrayMapping(unwrappedArray);\n\n                        }, null, { disposeWhenNodeIsRemoved: targetNode });\n                    }\n                };\n\n                var templateComputedDomDataKey = ko.utils.domData.nextKey();\n                function disposeOldComputedAndStoreNewOne(element, newComputed) {\n                    var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);\n                    if (oldComputed && (typeof(oldComputed.dispose) == 'function'))\n                        oldComputed.dispose();\n                    ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && (!newComputed.isActive || newComputed.isActive())) ? newComputed : undefined);\n                }\n\n                var cleanContainerDomDataKey = ko.utils.domData.nextKey();\n                ko.bindingHandlers['template'] = {\n                    'init': function(element, valueAccessor) {\n                        // Support anonymous templates\n                        var bindingValue = ko.utils.unwrapObservable(valueAccessor());\n                        if (typeof bindingValue == \"string\" || 'name' in bindingValue) {\n                            // It's a named template - clear the element\n                            ko.virtualElements.emptyNode(element);\n                        } else if ('nodes' in bindingValue) {\n                            // We've been given an array of DOM nodes. Save them as the template source.\n                            // There is no known use case for the node array being an observable array (if the output\n                            // varies, put that behavior *into* your template - that's what templates are for), and\n                            // the implementation would be a mess, so assert that it's not observable.\n                            var nodes = bindingValue['nodes'] || [];\n                            if (ko.isObservable(nodes)) {\n                                throw new Error('The \"nodes\" option must be a plain, non-observable array.');\n                            }\n\n                            // If the nodes are already attached to a KO-generated container, we reuse that container without moving the\n                            // elements to a new one (we check only the first node, as the nodes are always moved together)\n                            var container = nodes[0] && nodes[0].parentNode;\n                            if (!container || !ko.utils.domData.get(container, cleanContainerDomDataKey)) {\n                                container = ko.utils.moveCleanedNodesToContainerElement(nodes);\n                                ko.utils.domData.set(container, cleanContainerDomDataKey, true);\n                            }\n\n                            new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                        } else {\n                            // It's an anonymous template - store the element contents, then clear the element\n                            var templateNodes = ko.virtualElements.childNodes(element);\n                            if (templateNodes.length > 0) {\n                                var container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent\n                                new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                            } else {\n                                throw new Error(\"Anonymous template defined, but no template content was provided\");\n                            }\n                        }\n                        return { 'controlsDescendantBindings': true };\n                    },\n                    'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var value = valueAccessor(),\n                            options = ko.utils.unwrapObservable(value),\n                            shouldDisplay = true,\n                            templateComputed = null,\n                            template;\n\n                        if (typeof options == \"string\") {\n                            template = value;\n                            options = {};\n                        } else {\n                            template = 'name' in options ? options['name'] : element;\n\n                            // Support \"if\"/\"ifnot\" conditions\n                            if ('if' in options)\n                                shouldDisplay = ko.utils.unwrapObservable(options['if']);\n                            if (shouldDisplay && 'ifnot' in options)\n                                shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);\n\n                            // Don't show anything if an empty name is given (see #2446)\n                            if (shouldDisplay && !template) {\n                                shouldDisplay = false;\n                            }\n                        }\n\n                        if ('foreach' in options) {\n                            // Render once for each data point (treating data set as empty if shouldDisplay==false)\n                            var dataArray = (shouldDisplay && options['foreach']) || [];\n                            templateComputed = ko.renderTemplateForEach(template, dataArray, options, element, bindingContext);\n                        } else if (!shouldDisplay) {\n                            ko.virtualElements.emptyNode(element);\n                        } else {\n                            // Render once for this single data point (or use the viewModel if no data was provided)\n                            var innerBindingContext = bindingContext;\n                            if ('data' in options) {\n                                innerBindingContext = bindingContext['createChildContext'](options['data'], {\n                                    'as': options['as'],\n                                    'noChildContext': options['noChildContext'],\n                                    'exportDependencies': true\n                                });\n                            }\n                            templateComputed = ko.renderTemplate(template, innerBindingContext, options, element);\n                        }\n\n                        // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)\n                        disposeOldComputedAndStoreNewOne(element, templateComputed);\n                    }\n                };\n\n                // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.\n                ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {\n                    var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);\n\n                    if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])\n                        return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)\n\n                    if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, \"name\"))\n                        return null; // Named templates can be rewritten, so return \"no error\"\n                    return \"This template engine does not support anonymous templates nested within its templates\";\n                };\n\n                ko.virtualElements.allowedBindings['template'] = true;\n            })();\n\n            ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);\n            ko.exportSymbol('renderTemplate', ko.renderTemplate);\n// Go through the items that have been added and deleted and try to find matches between them.\n            ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {\n                if (left.length && right.length) {\n                    var failedCompares, l, r, leftItem, rightItem;\n                    for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {\n                        for (r = 0; rightItem = right[r]; ++r) {\n                            if (leftItem['value'] === rightItem['value']) {\n                                leftItem['moved'] = rightItem['index'];\n                                rightItem['moved'] = leftItem['index'];\n                                right.splice(r, 1);         // This item is marked as moved; so remove it from right list\n                                failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures\n                                break;\n                            }\n                        }\n                        failedCompares += r;\n                    }\n                }\n            };\n\n            ko.utils.compareArrays = (function () {\n                var statusNotInOld = 'added', statusNotInNew = 'deleted';\n\n                // Simple calculation based on Levenshtein distance.\n                function compareArrays(oldArray, newArray, options) {\n                    // For backward compatibility, if the third arg is actually a bool, interpret\n                    // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.\n                    options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});\n                    oldArray = oldArray || [];\n                    newArray = newArray || [];\n\n                    if (oldArray.length < newArray.length)\n                        return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);\n                    else\n                        return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);\n                }\n\n                function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {\n                    var myMin = Math.min,\n                        myMax = Math.max,\n                        editDistanceMatrix = [],\n                        smlIndex, smlIndexMax = smlArray.length,\n                        bigIndex, bigIndexMax = bigArray.length,\n                        compareRange = (bigIndexMax - smlIndexMax) || 1,\n                        maxDistance = smlIndexMax + bigIndexMax + 1,\n                        thisRow, lastRow,\n                        bigIndexMaxForRow, bigIndexMinForRow;\n\n                    for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {\n                        lastRow = thisRow;\n                        editDistanceMatrix.push(thisRow = []);\n                        bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);\n                        bigIndexMinForRow = myMax(0, smlIndex - 1);\n                        for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {\n                            if (!bigIndex)\n                                thisRow[bigIndex] = smlIndex + 1;\n                            else if (!smlIndex)  // Top row - transform empty array into new array via additions\n                                thisRow[bigIndex] = bigIndex + 1;\n                            else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])\n                                thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)\n                            else {\n                                var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)\n                                var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)\n                                thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;\n                            }\n                        }\n                    }\n\n                    var editScript = [], meMinusOne, notInSml = [], notInBig = [];\n                    for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {\n                        meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;\n                        if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {\n                            notInSml.push(editScript[editScript.length] = {     // added\n                                'status': statusNotInSml,\n                                'value': bigArray[--bigIndex],\n                                'index': bigIndex });\n                        } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {\n                            notInBig.push(editScript[editScript.length] = {     // deleted\n                                'status': statusNotInBig,\n                                'value': smlArray[--smlIndex],\n                                'index': smlIndex });\n                        } else {\n                            --bigIndex;\n                            --smlIndex;\n                            if (!options['sparse']) {\n                                editScript.push({\n                                    'status': \"retained\",\n                                    'value': bigArray[bigIndex] });\n                            }\n                        }\n                    }\n\n                    // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of\n                    // smlIndexMax keeps the time complexity of this algorithm linear.\n                    ko.utils.findMovesInArrayComparison(notInBig, notInSml, !options['dontLimitMoves'] && smlIndexMax * 10);\n\n                    return editScript.reverse();\n                }\n\n                return compareArrays;\n            })();\n\n            ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);\n            (function () {\n                // Objective:\n                // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,\n                //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node\n                // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node\n                //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we\n                //   previously mapped - retain those nodes, and just insert/delete other ones\n\n                // \"callbackAfterAddingNodes\" will be invoked after any \"mapping\"-generated nodes are inserted into the container node\n                // You can use this, for example, to activate bindings on those nodes.\n\n                function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {\n                    // Map this array value inside a dependentObservable so we re-map when any dependency changes\n                    var mappedNodes = [];\n                    var dependentObservable = ko.dependentObservable(function() {\n                        var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];\n\n                        // On subsequent evaluations, just replace the previously-inserted DOM nodes\n                        if (mappedNodes.length > 0) {\n                            ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);\n                            if (callbackAfterAddingNodes)\n                                ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);\n                        }\n\n                        // Replace the contents of the mappedNodes array, thereby updating the record\n                        // of which nodes would be deleted if valueToMap was itself later removed\n                        mappedNodes.length = 0;\n                        ko.utils.arrayPushAll(mappedNodes, newMappedNodes);\n                    }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });\n                    return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };\n                }\n\n                var lastMappingResultDomDataKey = ko.utils.domData.nextKey(),\n                    deletedItemDummyValue = ko.utils.domData.nextKey();\n\n                ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {\n                    array = array || [];\n                    if (typeof array.length == \"undefined\") // Coerce single value into array\n                        array = [array];\n\n                    options = options || {};\n                    var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey);\n                    var isFirstExecution = !lastMappingResult;\n\n                    // Build the new mapping result\n                    var newMappingResult = [];\n                    var lastMappingResultIndex = 0;\n                    var currentArrayIndex = 0;\n\n                    var nodesToDelete = [];\n                    var itemsToMoveFirstIndexes = [];\n                    var itemsForBeforeRemoveCallbacks = [];\n                    var itemsForMoveCallbacks = [];\n                    var itemsForAfterAddCallbacks = [];\n                    var mapData;\n                    var countWaitingForRemove = 0;\n\n                    function itemAdded(value) {\n                        mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };\n                        newMappingResult.push(mapData);\n                        if (!isFirstExecution) {\n                            itemsForAfterAddCallbacks.push(mapData);\n                        }\n                    }\n\n                    function itemMovedOrRetained(oldPosition) {\n                        mapData = lastMappingResult[oldPosition];\n                        if (currentArrayIndex !== mapData.indexObservable.peek())\n                            itemsForMoveCallbacks.push(mapData);\n                        // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray\n                        mapData.indexObservable(currentArrayIndex++);\n                        ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);\n                        newMappingResult.push(mapData);\n                    }\n\n                    function callCallback(callback, items) {\n                        if (callback) {\n                            for (var i = 0, n = items.length; i < n; i++) {\n                                ko.utils.arrayForEach(items[i].mappedNodes, function(node) {\n                                    callback(node, i, items[i].arrayEntry);\n                                });\n                            }\n                        }\n                    }\n\n                    if (isFirstExecution) {\n                        ko.utils.arrayForEach(array, itemAdded);\n                    } else {\n                        if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {\n                            // Compare the provided array against the previous one\n                            var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; }),\n                                compareOptions = {\n                                    'dontLimitMoves': options['dontLimitMoves'],\n                                    'sparse': true\n                                };\n                            editScript = ko.utils.compareArrays(lastArray, array, compareOptions);\n                        }\n\n                        for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {\n                            movedIndex = editScriptItem['moved'];\n                            itemIndex = editScriptItem['index'];\n                            switch (editScriptItem['status']) {\n                                case \"deleted\":\n                                    while (lastMappingResultIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex === undefined) {\n                                        mapData = lastMappingResult[lastMappingResultIndex];\n\n                                        // Stop tracking changes to the mapping for these nodes\n                                        if (mapData.dependentObservable) {\n                                            mapData.dependentObservable.dispose();\n                                            mapData.dependentObservable = undefined;\n                                        }\n\n                                        // Queue these nodes for later removal\n                                        if (ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {\n                                            if (options['beforeRemove']) {\n                                                newMappingResult.push(mapData);\n                                                countWaitingForRemove++;\n                                                if (mapData.arrayEntry === deletedItemDummyValue) {\n                                                    mapData = null;\n                                                } else {\n                                                    itemsForBeforeRemoveCallbacks.push(mapData);\n                                                }\n                                            }\n                                            if (mapData) {\n                                                nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);\n                                            }\n                                        }\n                                    }\n                                    lastMappingResultIndex++;\n                                    break;\n\n                                case \"added\":\n                                    while (currentArrayIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex !== undefined) {\n                                        itemsToMoveFirstIndexes.push(newMappingResult.length);\n                                        itemMovedOrRetained(movedIndex);\n                                    } else {\n                                        itemAdded(editScriptItem['value']);\n                                    }\n                                    break;\n                            }\n                        }\n\n                        while (currentArrayIndex < array.length) {\n                            itemMovedOrRetained(lastMappingResultIndex++);\n                        }\n\n                        // Record that the current view may still contain deleted items\n                        // because it means we won't be able to use a provided editScript.\n                        newMappingResult['_countWaitingForRemove'] = countWaitingForRemove;\n                    }\n\n                    // Store a copy of the array items we just considered so we can difference it next time\n                    ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);\n\n                    // Call beforeMove first before any changes have been made to the DOM\n                    callCallback(options['beforeMove'], itemsForMoveCallbacks);\n\n                    // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)\n                    ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);\n\n                    var i, j, lastNode, nodeToInsert, mappedNodes, activeElement;\n\n                    // Since most browsers remove the focus from an element when it's moved to another location,\n                    // save the focused element and try to restore it later.\n                    try {\n                        activeElement = domNode.ownerDocument.activeElement;\n                    } catch(e) {\n                        // IE9 throws if you access activeElement during page load (see issue #703)\n                    }\n\n                    // Try to reduce overall moved nodes by first moving the ones that were marked as moved by the edit script\n                    if (itemsToMoveFirstIndexes.length) {\n                        while ((i = itemsToMoveFirstIndexes.shift()) != undefined) {\n                            mapData = newMappingResult[i];\n                            for (lastNode = undefined; i; ) {\n                                if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) {\n                                    lastNode = mappedNodes[mappedNodes.length-1];\n                                    break;\n                                }\n                            }\n                            for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                                ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                            }\n                        }\n                    }\n\n                    // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)\n                    for (i = 0; mapData = newMappingResult[i]; i++) {\n                        // Get nodes for newly added items\n                        if (!mapData.mappedNodes)\n                            ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));\n\n                        // Put nodes in the right place if they aren't there already\n                        for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                            ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                        }\n\n                        // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)\n                        if (!mapData.initialized && callbackAfterAddingNodes) {\n                            callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);\n                            mapData.initialized = true;\n                            lastNode = mapData.mappedNodes[mapData.mappedNodes.length - 1];     // get the last node again since it may have been changed by a preprocessor\n                        }\n                    }\n\n                    // Restore the focused element if it had lost focus\n                    if (activeElement && domNode.ownerDocument.activeElement != activeElement) {\n                        activeElement.focus();\n                    }\n\n                    // If there's a beforeRemove callback, call it after reordering.\n                    // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using\n                    // some sort of animation, which is why we first reorder the nodes that will be removed. If the\n                    // callback instead removes the nodes right away, it would be more efficient to skip reordering them.\n                    // Perhaps we'll make that change in the future if this scenario becomes more common.\n                    callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);\n\n                    // Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item\n                    // as already \"removed\" so we won't call beforeRemove for it again, and it ensures that the item won't match up\n                    // with an actual item in the array and appear as \"retained\" or \"moved\".\n                    for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {\n                        itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;\n                    }\n\n                    // Finally call afterMove and afterAdd callbacks\n                    callCallback(options['afterMove'], itemsForMoveCallbacks);\n                    callCallback(options['afterAdd'], itemsForAfterAddCallbacks);\n                }\n            })();\n\n            ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);\n            ko.nativeTemplateEngine = function () {\n                this['allowTemplateRewriting'] = false;\n            }\n\n            ko.nativeTemplateEngine.prototype = new ko.templateEngine();\n            ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;\n            ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly\n                    templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,\n                    templateNodes = templateNodesFunc ? templateSource['nodes']() : null;\n\n                if (templateNodes) {\n                    return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);\n                } else {\n                    var templateText = templateSource['text']();\n                    return ko.utils.parseHtmlFragment(templateText, templateDocument);\n                }\n            };\n\n            ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();\n            ko.setTemplateEngine(ko.nativeTemplateEngine.instance);\n\n            ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);\n            (function() {\n                ko.jqueryTmplTemplateEngine = function () {\n                    // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl\n                    // doesn't expose a version number, so we have to infer it.\n                    // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,\n                    // which KO internally refers to as version \"2\", so older versions are no longer detected.\n                    var jQueryTmplVersion = this.jQueryTmplVersion = (function() {\n                        if (!jQueryInstance || !(jQueryInstance['tmpl']))\n                            return 0;\n                        // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.\n                        try {\n                            if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {\n                                // Since 1.0.0pre, custom tags should append markup to an array called \"__\"\n                                return 2; // Final version of jquery.tmpl\n                            }\n                        } catch(ex) { /* Apparently not the version we were looking for */ }\n\n                        return 1; // Any older version that we don't support\n                    })();\n\n                    function ensureHasReferencedJQueryTemplates() {\n                        if (jQueryTmplVersion < 2)\n                            throw new Error(\"Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.\");\n                    }\n\n                    function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {\n                        return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);\n                    }\n\n                    this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {\n                        templateDocument = templateDocument || document;\n                        options = options || {};\n                        ensureHasReferencedJQueryTemplates();\n\n                        // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)\n                        var precompiled = templateSource['data']('precompiled');\n                        if (!precompiled) {\n                            var templateText = templateSource['text']() || \"\";\n                            // Wrap in \"with($whatever.koBindingContext) { ... }\"\n                            templateText = \"{{ko_with $item.koBindingContext}}\" + templateText + \"{{/ko_with}}\";\n\n                            precompiled = jQueryInstance['template'](null, templateText);\n                            templateSource['data']('precompiled', precompiled);\n                        }\n\n                        var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays\n                        var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);\n\n                        var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);\n                        resultNodes['appendTo'](templateDocument.createElement(\"div\")); // Using \"appendTo\" forces jQuery/jQuery.tmpl to perform necessary cleanup work\n\n                        jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders\n                        return resultNodes;\n                    };\n\n                    this['createJavaScriptEvaluatorBlock'] = function(script) {\n                        return \"{{ko_code ((function() { return \" + script + \" })()) }}\";\n                    };\n\n                    this['addTemplate'] = function(templateName, templateMarkup) {\n                        document.write(\"<script type='text/html' id='\" + templateName + \"'>\" + templateMarkup + \"<\" + \"/script>\");\n                    };\n\n                    if (jQueryTmplVersion > 0) {\n                        jQueryInstance['tmpl']['tag']['ko_code'] = {\n                            open: \"__.push($1 || '');\"\n                        };\n                        jQueryInstance['tmpl']['tag']['ko_with'] = {\n                            open: \"with($1) {\",\n                            close: \"} \"\n                        };\n                    }\n                };\n\n                ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();\n                ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;\n\n                // Use this one by default *only if jquery.tmpl is referenced*\n                var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();\n                if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)\n                    ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);\n\n                ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);\n            })();\n        }));\n    }());\n})();\n","knockoutjs/knockout-fast-foreach.js":"/*!\n  Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z)\n  By: Brian M Hunt (C) 2015\n  License: MIT\n\n  Adds `fastForEach` to `ko.bindingHandlers`.\n*/\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    define(['knockout'], factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory(require('knockout'));\n  } else {\n    root.KnockoutFastForeach = factory(root.ko);\n  }\n}(this, function (ko) {\n  \"use strict\";\n// index.js\n// --------\n// Fast For Each\n//\n// Employing sound techniques to make a faster Knockout foreach binding.\n// --------\n\n//      Utilities\n\n// from https://github.com/jonschlinkert/is-plain-object\nfunction isPlainObject(o) {\n  return !!o && typeof o === 'object' && o.constructor === Object;\n}\n\n// From knockout/src/virtualElements.js\nvar commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\nvar startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\nvar supportsDocumentFragment = document && typeof document.createDocumentFragment === \"function\";\nfunction isVirtualNode(node) {\n  return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n}\n\n\n// Get a copy of the (possibly virtual) child nodes of the given element,\n// put them into a container, then empty the given node.\nfunction makeTemplateNode(sourceNode) {\n  var container = document.createElement(\"div\");\n  var parentNode;\n  if (sourceNode.content) {\n    // For e.g. <template> tags\n    parentNode = sourceNode.content;\n  } else if (sourceNode.tagName === 'SCRIPT') {\n    parentNode = document.createElement(\"div\");\n    parentNode.innerHTML = sourceNode.text;\n  } else {\n    // Anything else e.g. <div>\n    parentNode = sourceNode;\n  }\n  ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) {\n    // FIXME - This cloneNode could be expensive; we may prefer to iterate over the\n    // parentNode children in reverse (so as not to foul the indexes as childNodes are\n    // removed from parentNode when inserted into the container)\n    if (child) {\n      container.insertBefore(child.cloneNode(true), null);\n    }\n  });\n  return container;\n}\n\nfunction insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) {\n  var frag, len, i;\n  // poor man's node and array check, should be enough for this\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\" && typeof nodeOrNodeArrayToInsert.length === \"undefined\") {\n    throw new Error(\"Expected a single node or a node array\");\n  }\n\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\") {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode);\n    return;\n  }\n\n  if (nodeOrNodeArrayToInsert.length === 1) {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode);\n    return;\n  }\n\n  if (supportsDocumentFragment) {\n    frag = document.createDocumentFragment();\n\n    for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) {\n      frag.appendChild(nodeOrNodeArrayToInsert[i]);\n    }\n    ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode);\n  } else {\n    // Nodes are inserted in reverse order - pushed down immediately after\n    // the last node for the previous item or as the first node of element.\n    for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) {\n      var child = nodeOrNodeArrayToInsert[i];\n      if (!child) {\n        return;\n      }\n      ko.virtualElements.insertAfter(containerNode, child, insertAfterNode);\n    }\n  }\n}\n\n// Mimic a KO change item 'add'\nfunction valueToChangeAddItem(value, index) {\n  return {\n    status: 'added',\n    value: value,\n    index: index\n  };\n}\n\nfunction isAdditionAdjacentToLast(changeIndex, arrayChanges) {\n  return changeIndex > 0 &&\n    changeIndex < arrayChanges.length &&\n    arrayChanges[changeIndex].status === \"added\" &&\n    arrayChanges[changeIndex - 1].status === \"added\" &&\n    arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1;\n}\n\nfunction FastForEach(spec) {\n  this.element = spec.element;\n  this.container = isVirtualNode(this.element) ?\n                   this.element.parentNode : this.element;\n  this.$context = spec.$context;\n  this.data = spec.data;\n  this.as = spec.as;\n  this.noContext = spec.noContext;\n  this.templateNode = makeTemplateNode(\n    spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element\n  );\n  this.afterQueueFlush = spec.afterQueueFlush;\n  this.beforeQueueFlush = spec.beforeQueueFlush;\n  this.changeQueue = [];\n  this.lastNodesList = [];\n  this.indexesToDelete = [];\n  this.rendering_queued = false;\n\n  // Remove existing content.\n  ko.virtualElements.emptyNode(this.element);\n\n  // Prime content\n  var primeData = ko.unwrap(this.data);\n  if (primeData.map) {\n    this.onArrayChange(primeData.map(valueToChangeAddItem));\n  }\n\n  // Watch for changes\n  if (ko.isObservable(this.data)) {\n    if (!this.data.indexOf) {\n      // Make sure the observable is trackable.\n      this.data = this.data.extend({trackArrayChanges: true});\n    }\n    this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange');\n  }\n}\n\n\nFastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame ||\n  window.mozRequestAnimationFrame || window.msRequestAnimationFrame ||\n  function(cb) { return window.setTimeout(cb, 1000 / 60); };\n\n\nFastForEach.prototype.dispose = function () {\n  if (this.changeSubs) {\n    this.changeSubs.dispose();\n  }\n};\n\n\n// If the array changes we register the change.\nFastForEach.prototype.onArrayChange = function (changeSet) {\n  var self = this;\n  var changeMap = {\n    added: [],\n    deleted: []\n  };\n  for (var i = 0, len = changeSet.length; i < len; i++) {\n    // the change is appended to a last change info object when both are 'added' and have indexes next to each other\n    // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values\n    if (isAdditionAdjacentToLast(i, changeSet)) {\n      var batchValues = changeMap.added[changeMap.added.length - 1].values;\n      if (!batchValues) {\n        // transform the last addition into a batch addition object\n        var lastAddition = changeMap.added.pop();\n        var batchAddition = {\n          isBatch: true,\n          status: 'added',\n          index: lastAddition.index,\n          values: [lastAddition.value]\n        };\n        batchValues = batchAddition.values;\n        changeMap.added.push(batchAddition);\n      }\n      batchValues.push(changeSet[i].value);\n    } else {\n      changeMap[changeSet[i].status].push(changeSet[i]);\n    }\n  }\n  if (changeMap.deleted.length > 0) {\n    this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);\n    this.changeQueue.push({status: 'clearDeletedIndexes'});\n  }\n  this.changeQueue.push.apply(this.changeQueue, changeMap.added);\n  // Once a change is registered, the ticking count-down starts for the processQueue.\n  if (this.changeQueue.length > 0 && !this.rendering_queued) {\n    this.rendering_queued = true;\n    FastForEach.animateFrame.call(window, function () { self.processQueue(); });\n  }\n};\n\n\n// Reflect all the changes in the queue in the DOM, then wipe the queue.\nFastForEach.prototype.processQueue = function () {\n  var self = this;\n\n  // Callback so folks can do things before the queue flush.\n  if (typeof this.beforeQueueFlush === 'function') {\n    this.beforeQueueFlush(this.changeQueue);\n  }\n\n  ko.utils.arrayForEach(this.changeQueue, function (changeItem) {\n    // console.log(self.data(), \"CI\", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text()))\n    self[changeItem.status](changeItem);\n    // console.log(\"  ==> \", JSON.stringify($(self.element).text()))\n  });\n  this.rendering_queued = false;\n  // Callback so folks can do things.\n  if (typeof this.afterQueueFlush === 'function') {\n    this.afterQueueFlush(this.changeQueue);\n  }\n  this.changeQueue = [];\n};\n\n\n// Process a changeItem with {status: 'added', ...}\nFastForEach.prototype.added = function (changeItem) {\n  var index = changeItem.index;\n  var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value];\n  var referenceElement = this.lastNodesList[index - 1] || null;\n  // gather all childnodes for a possible batch insertion\n  var allChildNodes = [];\n\n  for (var i = 0, len = valuesToAdd.length; i < len; ++i) {\n    var templateClone = this.templateNode.cloneNode(true);\n    var childContext;\n\n    if (this.noContext) {\n      childContext = this.$context.extend({\n        '$item': valuesToAdd[i]\n      });\n    } else {\n      childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null);\n    }\n\n    // apply bindings first, and then process child nodes, because bindings can add childnodes\n    ko.applyBindingsToDescendants(childContext, templateClone);\n\n    var childNodes = ko.virtualElements.childNodes(templateClone);\n    // Note discussion at https://github.com/angular/angular.js/issues/7851\n    allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes));\n    this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]);\n  }\n\n  insertAllAfter(this.element, allChildNodes, referenceElement);\n};\n\n\n// Process a changeItem with {status: 'deleted', ...}\nFastForEach.prototype.deleted = function (changeItem) {\n  var index = changeItem.index;\n  var ptr = this.lastNodesList[index],\n      // We use this.element because that will be the last previous node\n      // for virtual element lists.\n      lastNode = this.lastNodesList[index - 1] || this.element;\n  do {\n    ptr = ptr.previousSibling;\n    ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element));\n  } while (ptr && ptr !== lastNode);\n  // The \"last node\" in the DOM from which we begin our delets of the next adjacent node is\n  // now the sibling that preceded the first node of this item.\n  this.lastNodesList[index] = this.lastNodesList[index - 1];\n  this.indexesToDelete.push(index);\n};\n\n\n// We batch our deletion of item indexes in our parallel array.\n// See brianmhunt/knockout-fast-foreach#6/#8\nFastForEach.prototype.clearDeletedIndexes = function () {\n  // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine\n  // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N.\n  for (var i = this.indexesToDelete.length - 1; i >= 0; --i) {\n    this.lastNodesList.splice(this.indexesToDelete[i], 1);\n  }\n  this.indexesToDelete = [];\n};\n\n\nko.bindingHandlers.fastForEach = {\n  // Valid valueAccessors:\n  //    []\n  //    ko.observable([])\n  //    ko.observableArray([])\n  //    ko.computed\n  //    {data: array, name: string, as: string}\n  init: function init(element, valueAccessor, bindings, vm, context) {\n    var value = valueAccessor(),\n        ffe;\n    if (isPlainObject(value)) {\n      value.element = value.element || element;\n      value.$context = context;\n      ffe = new FastForEach(value);\n    } else {\n      ffe = new FastForEach({\n        element: element,\n        data: ko.unwrap(context.$rawData) === value ? context.$rawData : value,\n        $context: context\n      });\n    }\n    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n      ffe.dispose();\n    });\n    return {controlsDescendantBindings: true};\n  },\n\n  // Export for testing, debugging, and overloading.\n  FastForEach: FastForEach\n};\n\nko.virtualElements.allowedBindings.fastForEach = true;\n}));","knockoutjs/knockout-repeat.js":"// REPEAT binding for Knockout http://knockoutjs.com/\n// (c) Michael Best\n// License: MIT (http://www.opensource.org/licenses/mit-license.php)\n// Version 2.1.0\n\n(function(factory) {\n    if (typeof define === 'function' && define.amd) {\n        // [1] AMD anonymous module\n        define(['knockout'], factory);\n    } else if (typeof exports === 'object') {\n        // [2] commonJS\n        factory(require('knockout'));\n    } else {\n        // [3] No module loader (plain <script> tag) - put directly in global namespace\n        factory(window.ko);\n    }\n})(function(ko) {\n\nif (!ko.virtualElements)\n    throw Error('Repeat requires at least Knockout 2.1');\n\nvar ko_bindingFlags = ko.bindingFlags || {};\nvar ko_unwrap = ko.utils.unwrapObservable;\n\nvar koProtoName = '__ko_proto__';\n\nif (ko.version >= \"3.0.0\") {\n    // In Knockout 3.0.0, use the node preprocessor to replace a node with a repeat binding with a virtual element\n    var provider = ko.bindingProvider.instance, previousPreprocessFn = provider.preprocessNode;\n    provider.preprocessNode = function(node) {\n        var newNodes, nodeBinding;\n        if (!previousPreprocessFn || !(newNodes = previousPreprocessFn.call(this, node))) {\n            if (node.nodeType === 1 && (nodeBinding = node.getAttribute('data-bind'))) {\n                if (/^\\s*repeat\\s*:/.test(nodeBinding)) {\n                    var leadingComment = node.ownerDocument.createComment('ko ' + nodeBinding),\n                        trailingComment = node.ownerDocument.createComment('/ko');\n                    node.parentNode.insertBefore(leadingComment, node);\n                    node.parentNode.insertBefore(trailingComment, node.nextSibling);\n                    node.removeAttribute('data-bind');\n                    newNodes = [leadingComment, node, trailingComment];\n                }\n            }\n        }\n        return newNodes;\n    };\n}\n\nko.virtualElements.allowedBindings.repeat = true;\nko.bindingHandlers.repeat = {\n    flags: ko_bindingFlags.contentBind | ko_bindingFlags.canUseVirtual,\n    init: function(element, valueAccessor, allBindingsAccessor, xxx, bindingContext) {\n\n        // Read and set fixed options--these options cannot be changed\n        var repeatParam = ko_unwrap(valueAccessor());\n        if (repeatParam && typeof repeatParam == 'object' && !('length' in repeatParam)) {\n            var repeatIndex = repeatParam.index,\n                repeatData = repeatParam.item,\n                repeatStep = repeatParam.step,\n                repeatReversed = repeatParam.reverse,\n                repeatBind = repeatParam.bind,\n                repeatInit = repeatParam.init,\n                repeatUpdate = repeatParam.update;\n        }\n        // Set default values for options that need it\n        repeatIndex = repeatIndex || '$index';\n        repeatData = repeatData || ko.bindingHandlers.repeat.itemName || '$item';\n        repeatStep = repeatStep || 1;\n        repeatReversed = repeatReversed || false;\n\n        var parent = element.parentNode, placeholder;\n        if (element.nodeType == 8) {    // virtual element\n            // Extract the \"children\" and find the single element node\n            var childNodes = ko.utils.arrayFilter(ko.virtualElements.childNodes(element), function(node) { return node.nodeType == 1;});\n            if (childNodes.length !== 1) {\n                throw Error(\"Repeat binding requires a single element to repeat\");\n            }\n            ko.virtualElements.emptyNode(element);\n\n            // The placeholder is the closing comment normally, or the opening comment if reversed\n            placeholder = repeatReversed ? element : element.nextSibling;\n            // The element to repeat is the contained element\n            element = childNodes[0];\n        } else {    // regular element\n            // First clean the element node and remove node's binding\n            var origBindString = element.getAttribute('data-bind');\n            ko.cleanNode(element);\n            element.removeAttribute('data-bind');\n\n            // Original element is no longer needed: delete it and create a placeholder comment\n            placeholder = element.ownerDocument.createComment('ko_repeatplaceholder ' + origBindString);\n            parent.replaceChild(placeholder, element);\n        }\n\n        // extract and remove a data-repeat-bind attribute, if present\n        if (!repeatBind) {\n            repeatBind = element.getAttribute('data-repeat-bind');\n            if (repeatBind) {\n                element.removeAttribute('data-repeat-bind');\n            }\n        }\n\n        // Make a copy of the element node to be copied for each repetition\n        var cleanNode = element.cloneNode(true);\n        if (typeof repeatBind == \"string\") {\n            cleanNode.setAttribute('data-bind', repeatBind);\n            repeatBind = null;\n        }\n\n        // Set up persistent data\n        var lastRepeatCount = 0,\n            notificationObservable = ko.observable(),\n            repeatArray, arrayObservable;\n\n        if (repeatInit) {\n            repeatInit(parent);\n        }\n\n        var subscribable = ko.computed(function() {\n            function makeArrayItemAccessor(index) {\n                var f = function(newValue) {\n                    var item = repeatArray[index];\n                    // Reading the value of the item\n                    if (!arguments.length) {\n                        notificationObservable();   // for dependency tracking\n                        return ko_unwrap(item);\n                    }\n                    // Writing a value to the item\n                    if (ko.isObservable(item)) {\n                        item(newValue);\n                    } else if (arrayObservable && arrayObservable.splice) {\n                        arrayObservable.splice(index, 1, newValue);\n                    } else {\n                        repeatArray[index] = newValue;\n                    }\n                    return this;\n                };\n                // Pretend that our accessor function is an observable\n                f[koProtoName] = ko.observable;\n                return f;\n            }\n\n            function makeBinding(item, index, context) {\n                return repeatArray\n                    ? function() { return repeatBind.call(bindingContext.$data, item, index, context); }\n                    : function() { return repeatBind.call(bindingContext.$data, index, context); }\n            }\n\n            // Read and set up variable options--these options can change and will update the binding\n            var paramObservable = valueAccessor(), repeatParam = ko_unwrap(paramObservable), repeatCount = 0;\n            if (repeatParam && typeof repeatParam == 'object') {\n                if ('length' in repeatParam) {\n                    repeatArray = repeatParam;\n                    repeatCount = repeatArray.length;\n                } else {\n                    if ('foreach' in repeatParam) {\n                        repeatArray = ko_unwrap(paramObservable = repeatParam.foreach);\n                        if (repeatArray && typeof repeatArray == 'object' && 'length' in repeatArray) {\n                            repeatCount = repeatArray.length || 0;\n                        } else {\n                            repeatCount = repeatArray || 0;\n                            repeatArray = null;\n                        }\n                    }\n                    // If a count value is provided (>0), always output that number of items\n                    if ('count' in repeatParam)\n                        repeatCount = ko_unwrap(repeatParam.count) || repeatCount;\n                    // If a limit is provided, don't output more than the limit\n                    if ('limit' in repeatParam)\n                        repeatCount = Math.min(repeatCount, ko_unwrap(repeatParam.limit)) || repeatCount;\n                }\n                arrayObservable = repeatArray && ko.isObservable(paramObservable) ? paramObservable : null;\n            } else {\n                repeatCount = repeatParam || 0;\n            }\n\n            // Remove nodes from end if array is shorter\n            for (; lastRepeatCount > repeatCount; lastRepeatCount-=repeatStep) {\n                ko.removeNode(repeatReversed ? placeholder.nextSibling : placeholder.previousSibling);\n            }\n\n            // Notify existing nodes of change\n            notificationObservable.notifySubscribers();\n\n            // Add nodes to end if array is longer (also initially populates nodes)\n            for (; lastRepeatCount < repeatCount; lastRepeatCount+=repeatStep) {\n                // Clone node and add to document\n                var newNode = cleanNode.cloneNode(true);\n                parent.insertBefore(newNode, repeatReversed ? placeholder.nextSibling : placeholder);\n                newNode.setAttribute('data-repeat-index', lastRepeatCount);\n\n                // Apply bindings to inserted node\n                if (repeatArray && repeatData == '$data') {\n                    var newContext = bindingContext.createChildContext(makeArrayItemAccessor(lastRepeatCount));\n                } else {\n                    var newContext = bindingContext.extend();\n                    if (repeatArray)\n                        newContext[repeatData] = makeArrayItemAccessor(lastRepeatCount);\n                }\n                newContext[repeatIndex] = lastRepeatCount;\n                if (repeatBind) {\n                    var result = ko.applyBindingsToNode(newNode, makeBinding(newContext[repeatData], lastRepeatCount, newContext), newContext, true),\n                        shouldBindDescendants = result && result.shouldBindDescendants;\n                }\n                if (!repeatBind || (result && shouldBindDescendants !== false)) {\n                    ko.applyBindings(newContext, newNode);\n                }\n            }\n            if (repeatUpdate) {\n                repeatUpdate(parent);\n            }\n        }, null, {disposeWhenNodeIsRemoved: placeholder});\n\n        return { controlsDescendantBindings: true, subscribable: subscribable };\n    }\n};\n});","vimeo/vimeo-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'vimeo'\n], function (Player) {\n    'use strict';\n\n    window.Vimeo = window.Vimeo || {\n        'Player': Player\n    };\n});\n","vimeo/player.min.js":"/*! @vimeo/player v2.16.4 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */\n!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):((e=\"undefined\"!=typeof globalThis?globalThis:e||self).Vimeo=e.Vimeo||{},e.Vimeo.Player=t())}(this,function(){\"use strict\";function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var e=\"undefined\"!=typeof global&&\"[object global]\"==={}.toString.call(global);function i(e,t){return 0===e.indexOf(t.toLowerCase())?e:\"\".concat(t.toLowerCase()).concat(e.substr(0,1).toUpperCase()).concat(e.substr(1))}function l(e){return/^(https?:)?\\/\\/((player|www)\\.)?vimeo\\.com(?=$|\\/)/.test(e)}function u(e){var t=0<arguments.length&&void 0!==e?e:{},n=t.id,e=t.url,t=n||e;if(!t)throw new Error(\"An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.\");if(e=t,!isNaN(parseFloat(e))&&isFinite(e)&&Math.floor(e)==e)return\"https://vimeo.com/\".concat(t);if(l(t))return t.replace(\"http:\",\"https:\");if(n)throw new TypeError(\"\u201c\".concat(n,\"\u201d is not a valid video id.\"));throw new TypeError(\"\u201c\".concat(t,\"\u201d is not a vimeo.com url.\"))}var t=void 0!==Array.prototype.indexOf,Player=\"undefined\"!=typeof window&&void 0!==window.postMessage;if(!(e||t&&Player))throw new Error(\"Sorry, the Vimeo Player API is not available in this browser.\");var n,o,a=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:{};function c(){if(void 0===this)throw new TypeError(\"Constructor WeakMap requires 'new'\");if(o(this,\"_id\",\"_WeakMap_\"+f()+\".\"+f()),0<arguments.length)throw new TypeError(\"WeakMap iterable is not supported\")}function s(e,t){if(!d(e)||!n.call(e,\"_id\"))throw new TypeError(t+\" method called on incompatible receiver \"+typeof e)}function f(){return Math.random().toString().substring(2)}function d(e){return Object(e)===e}(Player=\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:a).WeakMap||(n=Object.prototype.hasOwnProperty,Player.WeakMap=((o=function(e,t,n){Object.defineProperty?Object.defineProperty(e,t,{configurable:!0,writable:!0,value:n}):e[t]=n})(c.prototype,\"delete\",function(e){if(s(this,\"delete\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)&&(delete e[this._id],!0)}),o(c.prototype,\"get\",function(e){if(s(this,\"get\"),d(e)){var t=e[this._id];return t&&t[0]===e?t[1]:void 0}}),o(c.prototype,\"has\",function(e){if(s(this,\"has\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)}),o(c.prototype,\"set\",function(e,t){if(s(this,\"set\"),!d(e))throw new TypeError(\"Invalid value used as weak map key\");var n=e[this._id];return n&&n[0]===e?n[1]=t:o(e,this._id,[e,t]),this}),o(c,\"_polyfill\",!0),c));var h,m=(function(e){var t,n,r;r=function(){var t,n,r,o,i,e=Object.prototype.toString,a=\"undefined\"!=typeof setImmediate?function(e){return setImmediate(e)}:setTimeout;try{Object.defineProperty({},\"x\",{}),t=function(e,t,n,r){return Object.defineProperty(e,t,{value:n,writable:!0,configurable:!1!==r})}}catch(e){t=function(e,t,n){return e[t]=n,e}}function u(e,t){this.fn=e,this.self=t,this.next=void 0}function l(e,t){y.add(e,t),n=n||a(y.drain)}function c(e){var t,n=typeof e;return\"function\"==typeof(t=null!=e&&(\"object\"==n||\"function\"==n)?e.then:t)&&t}function s(){for(var e=0;e<this.chain.length;e++)!function(e,t,n){var r,o;try{!1===t?n.reject(e.msg):(r=!0===t?e.msg:t.call(void 0,e.msg))===n.promise?n.reject(TypeError(\"Promise-chain cycle\")):(o=c(r))?o.call(r,n.resolve,n.reject):n.resolve(r)}catch(e){n.reject(e)}}(this,1===this.state?this.chain[e].success:this.chain[e].failure,this.chain[e]);this.chain.length=0}function f(e){var n,r=this;if(!r.triggered){r.triggered=!0,r.def&&(r=r.def);try{(n=c(e))?l(function(){var t=new m(r);try{n.call(e,function(){f.apply(t,arguments)},function(){d.apply(t,arguments)})}catch(e){d.call(t,e)}}):(r.msg=e,r.state=1,0<r.chain.length&&l(s,r))}catch(e){d.call(new m(r),e)}}}function d(e){var t=this;t.triggered||(t.triggered=!0,(t=t.def?t.def:t).msg=e,t.state=2,0<t.chain.length&&l(s,t))}function h(e,n,r,o){for(var t=0;t<n.length;t++)!function(t){e.resolve(n[t]).then(function(e){r(t,e)},o)}(t)}function m(e){this.def=e,this.triggered=!1}function v(e){this.promise=e,this.state=0,this.triggered=!1,this.chain=[],this.msg=void 0}function p(e){if(\"function\"!=typeof e)throw TypeError(\"Not a function\");if(0!==this.__NPO__)throw TypeError(\"Not a promise\");this.__NPO__=1;var r=new v(this);this.then=function(e,t){var n={success:\"function\"!=typeof e||e,failure:\"function\"==typeof t&&t};return n.promise=new this.constructor(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");n.resolve=e,n.reject=t}),r.chain.push(n),0!==r.state&&l(s,r),n.promise},this.catch=function(e){return this.then(void 0,e)};try{e.call(void 0,function(e){f.call(r,e)},function(e){d.call(r,e)})}catch(e){d.call(r,e)}}var y={add:function(e,t){i=new u(e,t),o?o.next=i:r=i,o=i,i=void 0},drain:function(){var e=r;for(r=o=n=void 0;e;)e.fn.call(e.self),e=e.next}},g=t({},\"constructor\",p,!1);return t(p.prototype=g,\"__NPO__\",0,!1),t(p,\"resolve\",function(n){return n&&\"object\"==typeof n&&1===n.__NPO__?n:new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");e(n)})}),t(p,\"reject\",function(n){return new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");t(n)})}),t(p,\"all\",function(t){var a=this;return\"[object Array]\"!=e.call(t)?a.reject(TypeError(\"Not an array\")):0===t.length?a.resolve([]):new a(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");var r=t.length,o=Array(r),i=0;h(a,t,function(e,t){o[e]=t,++i===r&&n(o)},e)})}),t(p,\"race\",function(t){var r=this;return\"[object Array]\"!=e.call(t)?r.reject(TypeError(\"Not an array\")):new r(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");h(r,t,function(e,t){n(t)},e)})}),p},(n=a)[t=\"Promise\"]=n[t]||r(),e.exports&&(e.exports=n[t])}(h={exports:{}}),h.exports),v=new WeakMap;function p(e,t,n){var r=v.get(e.element)||{};t in r||(r[t]=[]),r[t].push(n),v.set(e.element,r)}function y(e,t){return(v.get(e.element)||{})[t]||[]}function g(e,t,n){var r=v.get(e.element)||{};if(!r[t])return!0;if(!n)return r[t]=[],v.set(e.element,r),!0;n=r[t].indexOf(n);return-1!==n&&r[t].splice(n,1),v.set(e.element,r),r[t]&&0===r[t].length}var w=[\"autopause\",\"autoplay\",\"background\",\"byline\",\"color\",\"controls\",\"dnt\",\"height\",\"id\",\"interactive_params\",\"keyboard\",\"loop\",\"maxheight\",\"maxwidth\",\"muted\",\"playsinline\",\"portrait\",\"responsive\",\"speed\",\"texttrack\",\"title\",\"transparent\",\"url\",\"width\"];function b(r,e){return w.reduce(function(e,t){var n=r.getAttribute(\"data-vimeo-\".concat(t));return!n&&\"\"!==n||(e[t]=\"\"===n?1:n),e},1<arguments.length&&void 0!==e?e:{})}function k(e,t){var n=e.html;if(!t)throw new TypeError(\"An element must be provided\");if(null!==t.getAttribute(\"data-vimeo-initialized\"))return t.querySelector(\"iframe\");e=document.createElement(\"div\");return e.innerHTML=n,t.appendChild(e.firstChild),t.setAttribute(\"data-vimeo-initialized\",\"true\"),t.querySelector(\"iframe\")}function E(i,e,t){var a=1<arguments.length&&void 0!==e?e:{},u=2<arguments.length?t:void 0;return new Promise(function(t,n){if(!l(i))throw new TypeError(\"\u201c\".concat(i,\"\u201d is not a vimeo.com url.\"));var e,r=\"https://vimeo.com/api/oembed.json?url=\".concat(encodeURIComponent(i));for(e in a)a.hasOwnProperty(e)&&(r+=\"&\".concat(e,\"=\").concat(encodeURIComponent(a[e])));var o=new(\"XDomainRequest\"in window?XDomainRequest:XMLHttpRequest);o.open(\"GET\",r,!0),o.onload=function(){if(404!==o.status)if(403!==o.status)try{var e=JSON.parse(o.responseText);if(403===e.domain_status_code)return k(e,u),void n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));t(e)}catch(e){n(e)}else n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));else n(new Error(\"\u201c\".concat(i,\"\u201d was not found.\")))},o.onerror=function(){var e=o.status?\" (\".concat(o.status,\")\"):\"\";n(new Error(\"There was an error fetching the embed code from Vimeo\".concat(e,\".\")))},o.send()})}function T(e){function n(e){\"console\"in window&&console.error&&console.error(\"There was an error creating an embed: \".concat(e))}e=0<arguments.length&&void 0!==e?e:document,e=[].slice.call(e.querySelectorAll(\"[data-vimeo-id], [data-vimeo-url]\"));e.forEach(function(t){try{if(null!==t.getAttribute(\"data-vimeo-defer\"))return;var e=b(t);E(u(e),e,t).then(function(e){return k(e,t)}).catch(n)}catch(e){n(e)}})}function P(e){if(\"string\"==typeof e)try{e=JSON.parse(e)}catch(e){return console.warn(e),{}}return e}function _(e,t,n){e.element.contentWindow&&e.element.contentWindow.postMessage&&(t={method:t},void 0!==n&&(t.value=n),8<=(n=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\\d+).*$/,\"$1\")))&&n<10&&(t=JSON.stringify(t)),e.element.contentWindow.postMessage(t,e.origin))}function M(n,r){var t,e,o,i,a=[];(r=P(r)).event?(\"error\"===r.event&&y(n,r.data.method).forEach(function(e){var t=new Error(r.data.message);t.name=r.data.name,e.reject(t),g(n,r.data.method,e)}),a=y(n,\"event:\".concat(r.event)),t=r.data):r.method&&(e=n,o=r.method,(i=!((i=y(e,o)).length<1)&&(i=i.shift(),g(e,o,i),i))&&(a.push(i),t=r.value)),a.forEach(function(e){try{if(\"function\"==typeof e)return void e.call(n,t);e.resolve(t)}catch(e){}})}var N,F,x,C=new WeakMap,j=new WeakMap,A={},Player=function(){function Player(i){var e,a=this,t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,Player),window.jQuery&&i instanceof jQuery&&(1<i.length&&window.console&&console.warn&&console.warn(\"A jQuery object with multiple elements was passed, using the first element.\"),i=i[0]),\"undefined\"!=typeof document&&\"string\"==typeof i&&(i=document.getElementById(i)),e=i,!Boolean(e&&1===e.nodeType&&\"nodeName\"in e&&e.ownerDocument&&e.ownerDocument.defaultView))throw new TypeError(\"You must pass either a valid element or a valid id.\");if(\"IFRAME\"===i.nodeName||(r=i.querySelector(\"iframe\"))&&(i=r),\"IFRAME\"===i.nodeName&&!l(i.getAttribute(\"src\")||\"\"))throw new Error(\"The player element passed isn\u2019t a Vimeo embed.\");if(C.has(i))return C.get(i);this._window=i.ownerDocument.defaultView,this.element=i,this.origin=\"*\";var n,r=new m(function(r,o){var e;a._onMessage=function(e){if(l(e.origin)&&a.element.contentWindow===e.source){\"*\"===a.origin&&(a.origin=e.origin);var t=P(e.data);if(t&&\"error\"===t.event&&t.data&&\"ready\"===t.data.method){var n=new Error(t.data.message);return n.name=t.data.name,void o(n)}e=t&&\"ready\"===t.event,n=t&&\"ping\"===t.method;if(e||n)return a.element.setAttribute(\"data-ready\",\"true\"),void r();M(a,t)}},a._window.addEventListener(\"message\",a._onMessage),\"IFRAME\"!==a.element.nodeName&&E(u(e=b(i,t)),e,i).then(function(e){var t,n,r=k(e,i);return a.element=r,a._originalElement=i,t=i,n=r,r=v.get(t),v.set(n,r),v.delete(t),C.set(a.element,a),e}).catch(o)});return j.set(this,r),C.set(this.element,this),\"IFRAME\"===this.element.nodeName&&_(this,\"ping\"),A.isEnabled&&(n=function(){return A.exit()},this.fullscreenchangeHandler=function(){(A.isFullscreen?p:g)(a,\"event:exitFullscreen\",n),a.ready().then(function(){_(a,\"fullscreenchange\",A.isFullscreen)})},A.on(\"fullscreenchange\",this.fullscreenchangeHandler)),this}var e,t,n;return e=Player,(t=[{key:\"callMethod\",value:function(n){var r=this,o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return new m(function(e,t){return r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n,o)}).catch(t)})}},{key:\"get\",value:function(n){var r=this;return new m(function(e,t){return n=i(n,\"get\"),r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n)}).catch(t)})}},{key:\"set\",value:function(n,r){var o=this;return new m(function(e,t){if(n=i(n,\"set\"),null==r)throw new TypeError(\"There must be a value to set.\");return o.ready().then(function(){p(o,n,{resolve:e,reject:t}),_(o,n,r)}).catch(t)})}},{key:\"on\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(!t)throw new TypeError(\"You must pass a callback function.\");if(\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");0===y(this,\"event:\".concat(e)).length&&this.callMethod(\"addEventListener\",e).catch(function(){}),p(this,\"event:\".concat(e),t)}},{key:\"off\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(t&&\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");g(this,\"event:\".concat(e),t)&&this.callMethod(\"removeEventListener\",e).catch(function(e){})}},{key:\"loadVideo\",value:function(e){return this.callMethod(\"loadVideo\",e)}},{key:\"ready\",value:function(){var e=j.get(this)||new m(function(e,t){t(new Error(\"Unknown player. Probably unloaded.\"))});return m.resolve(e)}},{key:\"addCuePoint\",value:function(e){return this.callMethod(\"addCuePoint\",{time:e,data:1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}})}},{key:\"removeCuePoint\",value:function(e){return this.callMethod(\"removeCuePoint\",e)}},{key:\"enableTextTrack\",value:function(e,t){if(!e)throw new TypeError(\"You must pass a language.\");return this.callMethod(\"enableTextTrack\",{language:e,kind:t})}},{key:\"disableTextTrack\",value:function(){return this.callMethod(\"disableTextTrack\")}},{key:\"pause\",value:function(){return this.callMethod(\"pause\")}},{key:\"play\",value:function(){return this.callMethod(\"play\")}},{key:\"requestFullscreen\",value:function(){return A.isEnabled?A.request(this.element):this.callMethod(\"requestFullscreen\")}},{key:\"exitFullscreen\",value:function(){return A.isEnabled?A.exit():this.callMethod(\"exitFullscreen\")}},{key:\"getFullscreen\",value:function(){return A.isEnabled?m.resolve(A.isFullscreen):this.get(\"fullscreen\")}},{key:\"requestPictureInPicture\",value:function(){return this.callMethod(\"requestPictureInPicture\")}},{key:\"exitPictureInPicture\",value:function(){return this.callMethod(\"exitPictureInPicture\")}},{key:\"getPictureInPicture\",value:function(){return this.get(\"pictureInPicture\")}},{key:\"unload\",value:function(){return this.callMethod(\"unload\")}},{key:\"destroy\",value:function(){var n=this;return new m(function(e){var t;j.delete(n),C.delete(n.element),n._originalElement&&(C.delete(n._originalElement),n._originalElement.removeAttribute(\"data-vimeo-initialized\")),n.element&&\"IFRAME\"===n.element.nodeName&&n.element.parentNode&&(n.element.parentNode.parentNode&&n._originalElement&&n._originalElement!==n.element.parentNode?n.element.parentNode.parentNode.removeChild(n.element.parentNode):n.element.parentNode.removeChild(n.element)),n.element&&\"DIV\"===n.element.nodeName&&n.element.parentNode&&(n.element.removeAttribute(\"data-vimeo-initialized\"),(t=n.element.querySelector(\"iframe\"))&&t.parentNode&&(t.parentNode.parentNode&&n._originalElement&&n._originalElement!==t.parentNode?t.parentNode.parentNode.removeChild(t.parentNode):t.parentNode.removeChild(t))),n._window.removeEventListener(\"message\",n._onMessage),A.isEnabled&&A.off(\"fullscreenchange\",n.fullscreenchangeHandler),e()})}},{key:\"getAutopause\",value:function(){return this.get(\"autopause\")}},{key:\"setAutopause\",value:function(e){return this.set(\"autopause\",e)}},{key:\"getBuffered\",value:function(){return this.get(\"buffered\")}},{key:\"getCameraProps\",value:function(){return this.get(\"cameraProps\")}},{key:\"setCameraProps\",value:function(e){return this.set(\"cameraProps\",e)}},{key:\"getChapters\",value:function(){return this.get(\"chapters\")}},{key:\"getCurrentChapter\",value:function(){return this.get(\"currentChapter\")}},{key:\"getColor\",value:function(){return this.get(\"color\")}},{key:\"setColor\",value:function(e){return this.set(\"color\",e)}},{key:\"getCuePoints\",value:function(){return this.get(\"cuePoints\")}},{key:\"getCurrentTime\",value:function(){return this.get(\"currentTime\")}},{key:\"setCurrentTime\",value:function(e){return this.set(\"currentTime\",e)}},{key:\"getDuration\",value:function(){return this.get(\"duration\")}},{key:\"getEnded\",value:function(){return this.get(\"ended\")}},{key:\"getLoop\",value:function(){return this.get(\"loop\")}},{key:\"setLoop\",value:function(e){return this.set(\"loop\",e)}},{key:\"setMuted\",value:function(e){return this.set(\"muted\",e)}},{key:\"getMuted\",value:function(){return this.get(\"muted\")}},{key:\"getPaused\",value:function(){return this.get(\"paused\")}},{key:\"getPlaybackRate\",value:function(){return this.get(\"playbackRate\")}},{key:\"setPlaybackRate\",value:function(e){return this.set(\"playbackRate\",e)}},{key:\"getPlayed\",value:function(){return this.get(\"played\")}},{key:\"getQualities\",value:function(){return this.get(\"qualities\")}},{key:\"getQuality\",value:function(){return this.get(\"quality\")}},{key:\"setQuality\",value:function(e){return this.set(\"quality\",e)}},{key:\"getSeekable\",value:function(){return this.get(\"seekable\")}},{key:\"getSeeking\",value:function(){return this.get(\"seeking\")}},{key:\"getTextTracks\",value:function(){return this.get(\"textTracks\")}},{key:\"getVideoEmbedCode\",value:function(){return this.get(\"videoEmbedCode\")}},{key:\"getVideoId\",value:function(){return this.get(\"videoId\")}},{key:\"getVideoTitle\",value:function(){return this.get(\"videoTitle\")}},{key:\"getVideoWidth\",value:function(){return this.get(\"videoWidth\")}},{key:\"getVideoHeight\",value:function(){return this.get(\"videoHeight\")}},{key:\"getVideoUrl\",value:function(){return this.get(\"videoUrl\")}},{key:\"getVolume\",value:function(){return this.get(\"volume\")}},{key:\"setVolume\",value:function(e){return this.set(\"volume\",e)}}])&&r(e.prototype,t),n&&r(e,n),Player}();return e||(N=function(){for(var e,t=[[\"requestFullscreen\",\"exitFullscreen\",\"fullscreenElement\",\"fullscreenEnabled\",\"fullscreenchange\",\"fullscreenerror\"],[\"webkitRequestFullscreen\",\"webkitExitFullscreen\",\"webkitFullscreenElement\",\"webkitFullscreenEnabled\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"webkitRequestFullScreen\",\"webkitCancelFullScreen\",\"webkitCurrentFullScreenElement\",\"webkitCancelFullScreen\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"mozRequestFullScreen\",\"mozCancelFullScreen\",\"mozFullScreenElement\",\"mozFullScreenEnabled\",\"mozfullscreenchange\",\"mozfullscreenerror\"],[\"msRequestFullscreen\",\"msExitFullscreen\",\"msFullscreenElement\",\"msFullscreenEnabled\",\"MSFullscreenChange\",\"MSFullscreenError\"]],n=0,r=t.length,o={};n<r;n++)if((e=t[n])&&e[1]in document){for(n=0;n<e.length;n++)o[t[0][n]]=e[n];return o}return!1}(),F={fullscreenchange:N.fullscreenchange,fullscreenerror:N.fullscreenerror},x={request:function(o){return new Promise(function(e,t){function n(){x.off(\"fullscreenchange\",n),e()}x.on(\"fullscreenchange\",n);var r=(o=o||document.documentElement)[N.requestFullscreen]();r instanceof Promise&&r.then(n).catch(t)})},exit:function(){return new Promise(function(t,e){var n,r;x.isFullscreen?(n=function e(){x.off(\"fullscreenchange\",e),t()},x.on(\"fullscreenchange\",n),(r=document[N.exitFullscreen]())instanceof Promise&&r.then(n).catch(e)):t()})},on:function(e,t){e=F[e];e&&document.addEventListener(e,t)},off:function(e,t){e=F[e];e&&document.removeEventListener(e,t)}},Object.defineProperties(x,{isFullscreen:{get:function(){return Boolean(document[N.fullscreenElement])}},element:{enumerable:!0,get:function(){return document[N.fullscreenElement]}},isEnabled:{enumerable:!0,get:function(){return Boolean(document[N.fullscreenEnabled])}}}),A=x,T(),function(e){var r=0<arguments.length&&void 0!==e?e:document;window.VimeoPlayerResizeEmbeds_||(window.VimeoPlayerResizeEmbeds_=!0,window.addEventListener(\"message\",function(e){if(l(e.origin)&&e.data&&\"spacechange\"===e.data.event)for(var t=r.querySelectorAll(\"iframe\"),n=0;n<t.length;n++)if(t[n].contentWindow===e.source){t[n].parentElement.style.paddingBottom=\"\".concat(e.data.data[0].bottom,\"px\");break}}))}()),Player});\n","Magento_Catalog/js/price-options.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'priceUtils',\n    'priceBox',\n    'jquery-ui-modules/widget'\n], function ($, _, mageTemplate, utils) {\n    'use strict';\n\n    var globalOptions = {\n        productId: null,\n        priceHolderSelector: '.price-box', //data-role=\"priceBox\"\n        optionsSelector: '.product-custom-option',\n        optionConfig: {},\n        optionHandlers: {},\n        optionTemplate: '<%= data.label %>' +\n        '<% if (data.finalPrice.value > 0) { %>' +\n        ' +<%- data.finalPrice.formatted %>' +\n        '<% } else if (data.finalPrice.value < 0) { %>' +\n        ' <%- data.finalPrice.formatted %>' +\n        '<% } %>',\n        controlContainer: 'dd'\n    };\n\n    /**\n     * Custom option preprocessor\n     * @param  {jQuery} element\n     * @param  {Object} optionsConfig - part of config\n     * @return {Object}\n     */\n    function defaultGetOptionValue(element, optionsConfig) {\n        var changes = {},\n            optionValue = element.val(),\n            optionId = utils.findOptionId(element[0]),\n            optionName = element.prop('name'),\n            optionType = element.prop('type'),\n            optionConfig = optionsConfig[optionId],\n            optionHash = optionName;\n\n        switch (optionType) {\n            case 'text':\n            case 'textarea':\n                changes[optionHash] = optionValue ? optionConfig.prices : {};\n                break;\n\n            case 'radio':\n                if (element.is(':checked')) {\n                    changes[optionHash] = optionConfig[optionValue] && optionConfig[optionValue].prices || {};\n                }\n                break;\n\n            case 'select-one':\n                changes[optionHash] = optionConfig[optionValue] && optionConfig[optionValue].prices || {};\n                break;\n\n            case 'select-multiple':\n                _.each(optionConfig, function (row, optionValueCode) {\n                    optionHash = optionName + '##' + optionValueCode;\n                    changes[optionHash] = _.contains(optionValue, optionValueCode) ? row.prices : {};\n                });\n                break;\n\n            case 'checkbox':\n                optionHash = optionName + '##' + optionValue;\n                changes[optionHash] = element.is(':checked') ? optionConfig[optionValue].prices : {};\n                break;\n\n            case 'file':\n                // Checking for 'disable' property equal to checking DOMNode with id*=\"change-\"\n                changes[optionHash] = optionValue || element.prop('disabled') ? optionConfig.prices : {};\n                break;\n        }\n\n        return changes;\n    }\n\n    $.widget('mage.priceOptions', {\n        options: globalOptions,\n\n        /**\n         * @private\n         */\n        _init: function initPriceBundle() {\n            $(this.options.optionsSelector, this.element).trigger('change');\n        },\n\n        /**\n         * Widget creating method.\n         * Triggered once.\n         * @private\n         */\n        _create: function createPriceOptions() {\n            var form = this.element,\n                options = $(this.options.optionsSelector, form),\n                priceBox = $(this.options.priceHolderSelector, $(this.options.optionsSelector).element);\n\n            if (priceBox.data('magePriceBox') &&\n                priceBox.priceBox('option') &&\n                priceBox.priceBox('option').priceConfig\n            ) {\n                if (priceBox.priceBox('option').priceConfig.optionTemplate) {\n                    this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);\n                }\n                this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);\n            }\n\n            this._applyOptionNodeFix(options);\n\n            options.on('change', this._onOptionChanged.bind(this));\n        },\n\n        /**\n         * Custom option change-event handler\n         * @param {Event} event\n         * @private\n         */\n        _onOptionChanged: function onOptionChanged(event) {\n            var changes,\n                option = $(event.target),\n                handler = this.options.optionHandlers[option.data('role')];\n\n            option.data('optionContainer', option.closest(this.options.controlContainer));\n\n            if (handler && handler instanceof Function) {\n                changes = handler(option, this.options.optionConfig, this);\n            } else {\n                changes = defaultGetOptionValue(option, this.options.optionConfig);\n            }\n            $(this.options.priceHolderSelector).trigger('updatePrice', changes);\n        },\n\n        /**\n         * Helper to fix issue with option nodes:\n         *  - you can't place any html in option ->\n         *    so you can't style it via CSS\n         * @param {jQuery} options\n         * @private\n         */\n        _applyOptionNodeFix: function applyOptionNodeFix(options) {\n            var config = this.options,\n                format = config.priceFormat,\n                template = config.optionTemplate;\n\n            template = mageTemplate(template);\n            options.filter('select').each(function (index, element) {\n                var $element = $(element),\n                    optionId = utils.findOptionId($element),\n                    optionConfig = config.optionConfig && config.optionConfig[optionId];\n\n                $element.find('option').each(function (idx, option) {\n                    var $option,\n                        optionValue,\n                        toTemplate,\n                        prices;\n\n                    $option = $(option);\n                    optionValue = $option.val();\n\n                    if (!optionValue && optionValue !== 0) {\n                        return;\n                    }\n\n                    toTemplate = {\n                        data: {\n                            label: optionConfig[optionValue] && optionConfig[optionValue].name\n                        }\n                    };\n                    prices = optionConfig[optionValue] ? optionConfig[optionValue].prices : null;\n\n                    if (prices) {\n                        _.each(prices, function (price, type) {\n                            var value = +price.amount;\n\n                            value += _.reduce(price.adjustments, function (sum, x) { //eslint-disable-line\n                                return sum + x;\n                            }, 0);\n                            toTemplate.data[type] = {\n                                value: value,\n                                formatted: utils.formatPriceLocale(value, format)\n                            };\n                        });\n\n                        $option.text(template(toTemplate));\n                    }\n                });\n            });\n        },\n\n        /**\n         * Custom behavior on getting options:\n         * now widget able to deep merge accepted configuration with instance options.\n         * @param  {Object}  options\n         * @return {$.Widget}\n         * @private\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n            this._super(options);\n\n            return this;\n        }\n    });\n\n    return $.mage.priceOptions;\n});\n","Magento_Catalog/js/price-option-date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'priceUtils',\n    'priceOptions',\n    'jquery-ui-modules/widget'\n], function ($, utils) {\n    'use strict';\n\n    var globalOptions = {\n            fromSelector: 'form',\n            dropdownsSelector: '[data-role=calendar-dropdown]'\n        },\n        optionHandler = {};\n\n    optionHandler.optionHandlers = {};\n\n    /**\n     * Custom handler for Date-with-Dropdowns option type.\n     * @param  {jQuery} siblings\n     * @return {Function} function that return object { optionHash : optionAdditionalPrice }\n     */\n    function onCalendarDropdownChange(siblings) {\n        return function (element, optionConfig) {\n            var changes = {},\n                optionId = utils.findOptionId(element),\n                overhead = optionConfig[optionId].prices,\n                isNeedToUpdate = true,\n                optionHash = 'price-option-calendar-' + optionId;\n\n            siblings.each(function (index, el) {\n                isNeedToUpdate = isNeedToUpdate && !!$(el).val();\n            });\n\n            overhead = isNeedToUpdate ? overhead : {};\n            changes[optionHash] = overhead;\n\n            return changes;\n        };\n    }\n\n    /**\n     * Returns number of days for special month and year\n     * @param  {Number} month\n     * @param  {Number} year\n     * @return {Number}\n     */\n    function getDaysInMonth(month, year) {\n        return new Date(year, month, 0).getDate();\n    }\n\n    /**\n     * Adjusts the number of days in the day option element based on which month or year\n     * is selected (changed). Adjusts the days to 28, 29, 30, or 31 typically.\n     * @param {jQuery} dropdowns\n     */\n    function onDateChange(dropdowns) {\n        var daysNodes,\n            curMonth, curYear, expectedDays,\n            options, needed,\n            month = dropdowns.filter('[data-calendar-role=month]'),\n            year = dropdowns.filter('[data-calendar-role=year]');\n\n        if (month.length && year.length) {\n            daysNodes = dropdowns.filter('[data-calendar-role=day]').find('option');\n\n            curMonth = month.val() || '01';\n            curYear = year.val() || '2000';\n            expectedDays = getDaysInMonth(curMonth, curYear);\n\n            if (daysNodes.length - 1 > expectedDays) { // remove unnecessary option nodes\n                daysNodes.each(function (i, e) {\n                    if (e.value > expectedDays) {\n                        $(e).remove();\n                    }\n                });\n            } else if (daysNodes.length - 1 < expectedDays) { // add missing option nodes\n                options = [];\n                needed = expectedDays - daysNodes.length + 1;\n\n                while (needed--) { //eslint-disable-line max-depth\n                    options.push(\n                        '<option value=\"' + (expectedDays - needed) + '\">' + (expectedDays - needed) + '</option>'\n                    );\n                }\n                $(options.join('')).insertAfter(daysNodes.last());\n            }\n        }\n    }\n\n    $.widget('mage.priceOptionDate', {\n        options: globalOptions,\n\n        /**\n         * Function-initializer of priceOptionDate widget\n         * @private\n         */\n        _create: function initOptionDate() {\n            var field = this.element,\n                form = field.closest(this.options.fromSelector),\n                dropdowns = $(this.options.dropdownsSelector, field),\n                dateOptionId;\n\n            if (dropdowns.length) {\n                dateOptionId = this.options.dropdownsSelector + dropdowns.attr('name');\n\n                optionHandler.optionHandlers[dateOptionId] = onCalendarDropdownChange(dropdowns);\n\n                form.priceOptions(optionHandler);\n\n                dropdowns.data('role', dateOptionId);\n                dropdowns.on('change', onDateChange.bind(this, dropdowns));\n            }\n        }\n    });\n\n    return $.mage.priceOptionDate;\n});\n","Magento_Catalog/js/price-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Catalog/js/price-utils',\n    'underscore',\n    'mage/template',\n    'jquery-ui-modules/widget'\n], function ($, utils, _, mageTemplate) {\n    'use strict';\n\n    var globalOptions = {\n        productId: null,\n        priceConfig: null,\n        prices: {},\n        priceTemplate: '<span class=\"price\"><%- data.formatted %></span>'\n    };\n\n    $.widget('mage.priceBox', {\n        options: globalOptions,\n        qtyInfo: '#qty',\n\n        /**\n         * Widget initialisation.\n         * Every time when option changed prices also can be changed. So\n         * changed options.prices -> changed cached prices -> recalculation -> redraw price box\n         */\n        _init: function initPriceBox() {\n            var box = this.element;\n\n            box.trigger('updatePrice');\n            this.cache.displayPrices = utils.deepClone(this.options.prices);\n        },\n\n        /**\n         * Widget creating.\n         */\n        _create: function createPriceBox() {\n            var box = this.element;\n\n            this.cache = {};\n            this._setDefaultsFromPriceConfig();\n            this._setDefaultsFromDataSet();\n\n            box.on('reloadPrice', this.reloadPrice.bind(this));\n            box.on('updatePrice', this.onUpdatePrice.bind(this));\n            $(this.qtyInfo).on('input', this.updateProductTierPrice.bind(this));\n            box.trigger('price-box-initialized');\n        },\n\n        /**\n         * Call on event updatePrice. Proxy to updatePrice method.\n         * @param {Event} event\n         * @param {Object} prices\n         */\n        onUpdatePrice: function onUpdatePrice(event, prices) {\n            return this.updatePrice(prices);\n        },\n\n        /**\n         * Updates price via new (or additional values).\n         * It expects object like this:\n         * -----\n         *   \"option-hash\":\n         *      \"price-code\":\n         *         \"amount\": 999.99999,\n         *         ...\n         * -----\n         * Empty option-hash object or empty price-code object treats as zero amount.\n         * @param {Object} newPrices\n         */\n        updatePrice: function updatePrice(newPrices) {\n            var prices = this.cache.displayPrices,\n                additionalPrice = {},\n                pricesCode = [],\n                priceValue, origin, finalPrice;\n\n            this.cache.additionalPriceObject = this.cache.additionalPriceObject || {};\n\n            if (newPrices) {\n                $.extend(this.cache.additionalPriceObject, newPrices);\n            }\n\n            if (!_.isEmpty(additionalPrice)) {\n                pricesCode = _.keys(additionalPrice);\n            } else if (!_.isEmpty(prices)) {\n                pricesCode = _.keys(prices);\n            }\n\n            _.each(this.cache.additionalPriceObject, function (additional) {\n                if (additional && !_.isEmpty(additional)) {\n                    pricesCode = _.keys(additional);\n                }\n                _.each(pricesCode, function (priceCode) {\n                    priceValue = additional[priceCode] || {};\n                    priceValue.amount = +priceValue.amount || 0;\n                    priceValue.adjustments = priceValue.adjustments || {};\n\n                    additionalPrice[priceCode] = additionalPrice[priceCode] || {\n                        'amount': 0,\n                        'adjustments': {}\n                    };\n                    additionalPrice[priceCode].amount =  0 + (additionalPrice[priceCode].amount || 0) +\n                        priceValue.amount;\n                    _.each(priceValue.adjustments, function (adValue, adCode) {\n                        additionalPrice[priceCode].adjustments[adCode] = 0 +\n                            (additionalPrice[priceCode].adjustments[adCode] || 0) + adValue;\n                    });\n                });\n            });\n\n            if (_.isEmpty(additionalPrice)) {\n                this.cache.displayPrices = utils.deepClone(this.options.prices);\n            } else {\n                _.each(additionalPrice, function (option, priceCode) {\n                    origin = this.options.prices[priceCode] || {};\n                    finalPrice = prices[priceCode] || {};\n                    option.amount = option.amount || 0;\n                    origin.amount = origin.amount || 0;\n                    origin.adjustments = origin.adjustments || {};\n                    finalPrice.adjustments = finalPrice.adjustments || {};\n\n                    finalPrice.amount = 0 + origin.amount + option.amount;\n                    _.each(option.adjustments, function (pa, paCode) {\n                        finalPrice.adjustments[paCode] = 0 + (origin.adjustments[paCode] || 0) + pa;\n                    });\n                }, this);\n            }\n\n            this.element.trigger('priceUpdated', this.cache.displayPrices);\n            this.element.trigger('reloadPrice');\n        },\n\n        /*eslint-disable no-extra-parens*/\n        /**\n         * Render price unit block.\n         */\n        reloadPrice: function reDrawPrices() {\n            var priceFormat = (this.options.priceConfig && this.options.priceConfig.priceFormat) || {},\n                priceTemplate = mageTemplate(this.options.priceTemplate);\n\n            _.each(this.cache.displayPrices, function (price, priceCode) {\n                price.final = _.reduce(price.adjustments, function (memo, amount) {\n                    return memo + amount;\n                }, price.amount);\n\n                price.formatted = utils.formatPriceLocale(price.final, priceFormat);\n\n                $('[data-price-type=\"' + priceCode + '\"]', this.element).html(priceTemplate({\n                    data: price\n                }));\n            }, this);\n        },\n\n        /*eslint-enable no-extra-parens*/\n        /**\n         * Overwrites initial (default) prices object.\n         * @param {Object} prices\n         */\n        setDefault: function setDefaultPrices(prices) {\n            this.cache.displayPrices = utils.deepClone(prices);\n            this.options.prices = utils.deepClone(prices);\n        },\n\n        /**\n         * Custom behavior on getting options:\n         * now widget able to deep merge of accepted configuration.\n         * @param  {Object} options\n         * @return {mage.priceBox}\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n\n            if ('disabled' in options) {\n                this._setOption('disabled', options.disabled);\n            }\n\n            return this;\n        },\n\n        /**\n         * setDefaultsFromDataSet\n         */\n        _setDefaultsFromDataSet: function _setDefaultsFromDataSet() {\n            var box = this.element,\n                priceHolders = $('[data-price-type]', box),\n                prices = this.options.prices;\n\n            this.options.productId = box.data('productId');\n\n            if (_.isEmpty(prices)) {\n                priceHolders.each(function (index, element) {\n                    var type = $(element).data('priceType'),\n                        amount = parseFloat($(element).data('priceAmount'));\n\n                    if (type && !_.isNaN(amount)) {\n                        prices[type] = {\n                            amount: amount\n                        };\n                    }\n                });\n            }\n        },\n\n        /**\n         * setDefaultsFromPriceConfig\n         */\n        _setDefaultsFromPriceConfig: function _setDefaultsFromPriceConfig() {\n            var config = this.options.priceConfig;\n\n            if (config && config.prices) {\n                this.options.prices = config.prices;\n            }\n        },\n\n        /**\n         * Updates product final and base price according to tier prices\n         */\n        updateProductTierPrice: function updateProductTierPrice() {\n            var originalPrice,\n                prices = {'prices': {}};\n\n            if (this.options.prices.finalPrice) {\n                originalPrice = this.options.prices.finalPrice.amount;\n                prices.prices.finalPrice = {'amount': this.getPrice('price') - originalPrice};\n            }\n\n            if (this.options.prices.basePrice) {\n                originalPrice = this.options.prices.basePrice.amount;\n                prices.prices.basePrice = {'amount': this.getPrice('basePrice') - originalPrice};\n            }\n\n            this.updatePrice(prices);\n        },\n\n        /**\n         * Returns price.\n         *\n         * @param {String} priceKey\n         * @returns {Number}\n         */\n        getPrice: function (priceKey) {\n            var productQty = $(this.qtyInfo).val(),\n                result,\n                tierPriceItem,\n                i;\n\n            for (i = 0; i < this.options.priceConfig.tierPrices.length; i++) {\n                tierPriceItem = this.options.priceConfig.tierPrices[i];\n                if (productQty >= tierPriceItem.qty && tierPriceItem[priceKey]) {\n                    result = tierPriceItem[priceKey];\n                }\n            }\n\n            return result;\n        }\n    });\n\n    return $.mage.priceBox;\n});\n","Magento_Catalog/js/price-utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore'\n], function ($, _) {\n    'use strict';\n\n    var globalPriceFormat = {\n        requiredPrecision: 2,\n        integerRequired: 1,\n        decimalSymbol: ',',\n        groupSymbol: ',',\n        groupLength: ','\n    };\n\n    /**\n     * Repeats {string} {times} times\n     * @param  {String} string\n     * @param  {Number} times\n     * @return {String}\n     */\n    function stringPad(string, times) {\n        return new Array(times + 1).join(string);\n    }\n\n    /**\n     * Format the price with the compliance to the specified locale\n     *\n     * @param {Number} amount\n     * @param {Object} format\n     * @param  {Boolean} isShowSign\n     */\n    function formatPriceLocale(amount, format, isShowSign)\n    {\n        var s = '',\n            precision, pattern, locale, r;\n\n        format = _.extend(globalPriceFormat, format);\n        precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;\n        pattern = format.pattern || '%s';\n        locale = window.LOCALE || 'en-US';\n        if (isShowSign === undefined || isShowSign === true) {\n            s = amount < 0 ? '-' : isShowSign ? '+' : '';\n        } else if (isShowSign === false) {\n            s = '';\n        }\n        pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s);\n        amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision));\n        r = amount.toLocaleString(locale, {minimumFractionDigits: precision});\n\n        return pattern.replace('%s', r).replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n    }\n\n    /**\n     * Formatter for price amount\n     * @param  {Number}  amount\n     * @param  {Object}  format\n     * @param  {Boolean} isShowSign\n     * @return {String}              Formatted value\n     * @deprecated\n     */\n    function formatPrice(amount, format, isShowSign) {\n        var s = '',\n            precision, integerRequired, decimalSymbol, groupSymbol, groupLength, pattern, i, pad, j, re, r, am;\n\n        format = _.extend(globalPriceFormat, format);\n\n        // copied from price-option.js | Could be refactored with varien/js.js\n\n        precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;\n        integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired;\n        decimalSymbol = format.decimalSymbol === undefined ? ',' : format.decimalSymbol;\n        groupSymbol = format.groupSymbol === undefined ? '.' : format.groupSymbol;\n        groupLength = format.groupLength === undefined ? 3 : format.groupLength;\n        pattern = format.pattern || '%s';\n\n        if (isShowSign === undefined || isShowSign === true) {\n            s = amount < 0 ? '-' : isShowSign ? '+' : '';\n        } else if (isShowSign === false) {\n            s = '';\n        }\n        pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s);\n\n        // we're avoiding the usage of to fixed, and using round instead with the e representation to address\n        // numbers like 1.005 = 1.01. Using ToFixed to only provide trailing zeroes in case we have a whole number\n        i = parseInt(\n                amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision)),\n                10\n            ) + '';\n        pad = i.length < integerRequired ? integerRequired - i.length : 0;\n\n        i = stringPad('0', pad) + i;\n\n        j = i.length > groupLength ? i.length % groupLength : 0;\n        re = new RegExp('(\\\\d{' + groupLength + '})(?=\\\\d)', 'g');\n\n        // replace(/-/, 0) is only for fixing Safari bug which appears\n        // when Math.abs(0).toFixed() executed on '0' number.\n        // Result is '0.-0' :(\n\n        am = Number(Math.round(Math.abs(amount - i) + 'e+' + precision) + ('e-' + precision));\n        r = (j ? i.substr(0, j) + groupSymbol : '') +\n            i.substr(j).replace(re, '$1' + groupSymbol) +\n            (precision ? decimalSymbol + am.toFixed(precision).replace(/-/, 0).slice(2) : '');\n\n        return pattern.replace('%s', r).replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n    }\n\n    /**\n     * Deep clone of Object. Doesn't support functions\n     * @param {Object} obj\n     * @return {Object}\n     */\n    function objectDeepClone(obj) {\n        return JSON.parse(JSON.stringify(obj));\n    }\n\n    /**\n     * Helper to find ID in name attribute\n     * @param   {jQuery} element\n     * @returns {undefined|String}\n     */\n    function findOptionId(element) {\n        var re, id, name;\n\n        if (!element) {\n            return id;\n        }\n        name = $(element).attr('name');\n\n        if (name.indexOf('[') !== -1) {\n            re = /\\[([^\\]]+)?\\]/;\n        } else {\n            re = /_([^\\]]+)?_/; // just to support file-type-option\n        }\n        id = re.exec(name) && re.exec(name)[1];\n\n        if (id) {\n            return id;\n        }\n    }\n\n    return {\n        formatPriceLocale: formatPriceLocale,\n        formatPrice: formatPrice,\n        deepClone: objectDeepClone,\n        strPad: stringPad,\n        findOptionId: findOptionId\n    };\n});\n","Magento_Catalog/js/price-option-file.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.priceOptionFile', {\n        options: {\n            fileName: '',\n            fileNamed: '',\n            fieldNameAction: '',\n            changeFileSelector: '',\n            deleteFileSelector: ''\n        },\n\n        /**\n         * Creates instance of widget\n         * @private\n         */\n        _create: function () {\n            this.fileDeleteFlag = this.fileChangeFlag = false;\n            this.inputField = this.element.find('input[name=' + this.options.fileName + ']')[0];\n            this.inputFieldAction = this.element.find('input[name=' + this.options.fieldNameAction + ']')[0];\n            this.fileNameSpan = this.element.parent('dd').find('.' + this.options.fileNamed);\n\n            $(this.options.changeFileSelector).on('click', $.proxy(function () {\n                this._toggleFileChange();\n            }, this));\n            $(this.options.deleteFileSelector).on('click', $.proxy(function () {\n                this._toggleFileDelete();\n            }, this));\n        },\n\n        /**\n         * Toggles whether the current file is being changed or not. If the file is being deleted\n         * then the option to change the file is disabled.\n         * @private\n         */\n        _toggleFileChange: function () {\n            this.element.toggle();\n            this.fileChangeFlag = !this.fileChangeFlag;\n\n            if (!this.fileDeleteFlag) {\n                $(this.inputFieldAction).attr('value', this.fileChangeFlag ? 'save_new' : 'save_old');\n                this.inputField.disabled = !this.fileChangeFlag;\n            }\n        },\n\n        /**\n         * Toggles whether the file is to be deleted. When the file is being deleted, the name of\n         * the file is decorated with strike-through text and the option to change the file is\n         * disabled.\n         * @private\n         */\n        _toggleFileDelete: function () {\n            this.fileDeleteFlag = $(this.options.deleteFileSelector + ':checked').val();\n            $(this.inputFieldAction).attr('value',\n                this.fileDeleteFlag ? '' : this.fileChangeFlag ? 'save_new' : 'save_old');\n            this.inputField.disabled = this.fileDeleteFlag || !this.fileChangeFlag;\n            this.fileNameSpan.css('text-decoration', this.fileDeleteFlag ? 'line-through' : 'none');\n        }\n    });\n\n    return $.mage.priceOptionFile;\n});\n","Magento_Catalog/js/validate-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'mage/mage',\n    'Magento_Catalog/product/view/validation',\n    'catalogAddToCart'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.productValidate', {\n        options: {\n            bindSubmit: false,\n            radioCheckboxClosest: '.nested',\n            addToCartButtonSelector: '.action.tocart'\n        },\n\n        /**\n         * Uses Magento's validation widget for the form object.\n         * @private\n         */\n        _create: function () {\n            var bindSubmit = this.options.bindSubmit;\n\n            this.element.validation({\n                radioCheckboxClosest: this.options.radioCheckboxClosest,\n\n                /**\n                 * Uses catalogAddToCart widget as submit handler.\n                 * @param {Object} form\n                 * @returns {Boolean}\n                 */\n                submitHandler: function (form) {\n                    var jqForm = $(form).catalogAddToCart({\n                        bindSubmit: bindSubmit\n                    });\n\n                    jqForm.catalogAddToCart('submitForm', jqForm);\n\n                    return false;\n                }\n            });\n            $(this.options.addToCartButtonSelector).attr('disabled', false);\n        }\n    });\n\n    return $.mage.productValidate;\n});\n","Magento_Catalog/js/related-products.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget',\n    'mage/translate'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.relatedProducts', {\n        options: {\n            relatedCheckbox: '.related-checkbox', // Class name for a related product's input checkbox.\n            relatedProductsCheckFlag: false, // Related products checkboxes are initially unchecked.\n            relatedProductsField: '#related-products-field', // Hidden input field that stores related products.\n            selectAllMessage: $.mage.__('select all'),\n            unselectAllMessage: $.mage.__('unselect all'),\n            selectAllLink: '[data-role=\"select-all\"]',\n            elementsSelector: '.item.product'\n        },\n\n        /**\n         * Bind events to the appropriate handlers.\n         * @private\n         */\n        _create: function () {\n            $(this.options.selectAllLink, this.element).on('click', $.proxy(this._selectAllRelated, this));\n            $(this.options.relatedCheckbox, this.element).on('click', $.proxy(this._addRelatedToProduct, this));\n\n            if (this.element.data('shuffle')) {\n                this._shuffle(this.element.find(this.options.elementsSelector));\n            }\n            this._showRelatedProducts(\n                this.element.find(this.options.elementsSelector),\n                this.element.data('limit'),\n                this.element.data('shuffle-weighted')\n            );\n        },\n\n        /**\n         * This method either checks all checkboxes for a product's set of related products (select all)\n         * or unchecks them (unselect all).\n         * @private\n         * @param {jQuery.Event} e - Click event on either the \"select all\" link or the \"unselect all\" link.\n         * @return {Boolean} - Prevent default event action and event propagation.\n         */\n        _selectAllRelated: function (e) {\n            var innerHTML = this.options.relatedProductsCheckFlag ?\n                this.options.selectAllMessage : this.options.unselectAllMessage;\n\n            $(e.target).html(innerHTML);\n            $(this.options.relatedCheckbox + ':visible').attr(\n                'checked',\n                this.options.relatedProductsCheckFlag = !this.options.relatedProductsCheckFlag\n            );\n            this._addRelatedToProduct();\n\n            return false;\n        },\n\n        /**\n         * This method iterates through each checkbox for all related products and collects only those products\n         * whose checkbox has been checked. The selected related products are stored in a hidden input field.\n         * @private\n         */\n        _addRelatedToProduct: function () {\n            $(this.options.relatedProductsField).val(\n                $(this.options.relatedCheckbox + ':checked').map(function () {\n                    return this.value;\n                }).get().join(',')\n            );\n        },\n\n        /* jscs:disable */\n        /* eslint-disable */\n        /**\n         * Show related products according to limit. Shuffle if needed.\n         * @param {*} elements\n         * @param {*} limit\n         * @param weightedRandom\n         * @private\n         */\n        _showRelatedProducts: function (elements, limit, weightedRandom) {\n            var index, weights = [], random = [], weight = 2, shown = 0, $element, currentGroup, prevGroup;\n\n            if (limit === 0) {\n                limit = elements.length;\n            }\n\n            if (weightedRandom && limit > 0 && limit < elements.length) {\n                for (index = 0; index < limit; index++) {\n                    $element = $(elements[index]);\n                    if ($element.data('shuffle-group') !== '') {\n                        break;\n                    }\n                    $element.show();\n                    shown++;\n                }\n                limit -= shown;\n                for (index = elements.length - 1; index >= 0; index--) {\n                    $element = $(elements[index]);\n                    currentGroup = $element.data('shuffle-group');\n                    if (currentGroup !== '') {\n                        weights.push([index, Math.log(weight)]);\n                        if (typeof prevGroup !== 'undefined' && prevGroup !== currentGroup) {\n                            weight += 2;\n                        }\n                        prevGroup = currentGroup;\n                    }\n                }\n\n                if (weights.length === 0) {\n                    return;\n                }\n\n                for (index = 0; index < weights.length; index++) {\n                    random.push([weights[index][0], Math.pow(Math.random(), 1 / weights[index][1])]);\n                }\n\n                random.sort(function(a, b) {\n                    a = a[1];\n                    b = b[1];\n                    return a < b ? 1 : (a > b ? -1 : 0);\n                });\n                index = 0;\n                while (limit) {\n                    $(elements[random[index][0]]).show();\n                    limit--;\n                    index++\n                }\n                return;\n            }\n\n            for (index = 0; index < limit; index++) {\n                $(elements[index]).show();\n            }\n        },\n\n        /* jscs:disable */\n        /* eslint-disable */\n        /**\n         * Shuffle an array\n         * @param {Array} elements\n         * @returns {*}\n         */\n        _shuffle: function shuffle(elements) {\n            var parent, child, lastSibling;\n            if (elements.length) {\n                parent = $(elements[0]).parent();\n            }\n            while (elements.length) {\n                child = elements.splice(Math.floor(Math.random() *  elements.length), 1)[0];\n                lastSibling = parent.find('[data-shuffle-group=\"' + $(child).data('shuffle-group') + '\"]').last();\n                lastSibling.after(child);\n            }\n        }\n\n        /* jscs:disable */\n        /* eslint:disable */\n    });\n\n    return $.mage.relatedProducts;\n});\n","Magento_Catalog/js/gallery.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.gallery', {\n        options: {\n            minWidth: 300, // Minimum width of the gallery image.\n            widthOffset: 90, // Offset added to the width of the gallery image.\n            heightOffset: 210, // Offset added to the height of the gallery image.\n            closeWindow: 'div.buttons-set a[role=\"close-window\"]' // Selector for closing the gallery popup window.\n        },\n\n        /**\n         * Bind click handler for closing the popup window and resize the popup based on the image size.\n         * @private\n         */\n        _create: function () {\n            $(this.options.closeWindow).on('click', function () {\n                window.close();\n            });\n            this._resizeWindow();\n        },\n\n        /**\n         * Resize the gallery image popup window based on the image's dimensions.\n         * @private\n         */\n        _resizeWindow: function () {\n            var img = this.element,\n                width = img.width() < this.options.minWidth ? this.options.minWidth : img.width();\n\n            window.resizeTo(width + this.options.widthOffset, img.height() + this.options.heightOffset);\n        }\n    });\n\n    return $.mage.gallery;\n});\n","Magento_Catalog/js/upsell-products.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.upsellProducts', {\n        options: {\n            elementsSelector: '.item.product'\n        },\n\n        /**\n         * Bind events to the appropriate handlers.\n         * @private\n         */\n        _create: function () {\n            if (this.element.data('shuffle')) {\n                this._shuffle(this.element.find(this.options.elementsSelector));\n            }\n            this._showUpsellProducts(\n                this.element.find(this.options.elementsSelector),\n                this.element.data('limit'),\n                this.element.data('shuffle-weighted')\n            );\n        },\n\n        /* jscs:disable */\n        /* eslint-disable */\n        /**\n         * Show upsell products according to limit. Shuffle if needed.\n         * @param {*} elements\n         * @param {Number} limit\n         * @param {Boolean} weightedRandom\n         * @private\n         */\n        _showUpsellProducts: function (elements, limit, weightedRandom) {\n            var index, weights = [], random = [], weight = 2, shown = 0, $element, currentGroup, prevGroup;\n\n            if (limit === 0) {\n                limit = elements.length;\n            }\n\n            if (weightedRandom && limit > 0 && limit < elements.length) {\n                for (index = 0; index < limit; index++) {\n                    $element = $(elements[index]);\n                    if ($element.data('shuffle-group') !== '') {\n                        break;\n                    }\n                    $element.show();\n                    shown++;\n                }\n                limit -= shown;\n                for (index = elements.length - 1; index >= 0; index--) {\n                    $element = $(elements[index]);\n                    currentGroup = $element.data('shuffle-group');\n                    if (currentGroup !== '') {\n                        weights.push([index, Math.log(weight)]);\n                        if (typeof prevGroup !== 'undefined' && prevGroup !== currentGroup) {\n                            weight += 2;\n                        }\n                        prevGroup = currentGroup;\n                    }\n                }\n\n                if (weights.length === 0) {\n                    return;\n                }\n\n                for (index = 0; index < weights.length; index++) {\n                    random.push([weights[index][0], Math.pow(Math.random(), 1 / weights[index][1])]);\n                }\n\n                random.sort(function(a, b) {\n                    a = a[1];\n                    b = b[1];\n                    return a < b ? 1 : (a > b ? -1 : 0);\n                });\n                index = 0;\n                while (limit) {\n                    $(elements[random[index][0]]).show();\n                    limit--;\n                    index++\n                }\n                return;\n            }\n\n            for (index = 0; index < limit; index++) {\n                $(elements[index]).show();\n            }\n        },\n\n        /* jscs:disable */\n        /* eslint-disable */\n        /**\n         * Shuffle an array\n         * @param elements\n         * @returns {*}\n         */\n        _shuffle: function shuffle(elements){ //v1.0\n            var parent, child, lastSibling;\n            if (elements.length) {\n                parent = $(elements[0]).parent();\n            }\n            while (elements.length) {\n                child = elements.splice(Math.floor(Math.random() *  elements.length), 1)[0];\n                lastSibling = parent.find('[data-shuffle-group=\"' + $(child).data('shuffle-group') + '\"]').last();\n                lastSibling.after(child);\n            }\n        }\n\n        /* jscs:disable */\n        /* eslint:disable */\n    });\n\n    return $.mage.upsellProducts;\n});\n","Magento_Catalog/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/translate',\n    'underscore',\n    'Magento_Catalog/js/product/view/product-ids-resolver',\n    'Magento_Catalog/js/product/view/product-info-resolver',\n    'jquery-ui-modules/widget'\n], function ($, $t, _, idsResolver, productInfoResolver) {\n    'use strict';\n\n    $.widget('mage.catalogAddToCart', {\n        options: {\n            processStart: null,\n            processStop: null,\n            bindSubmit: true,\n            minicartSelector: '[data-block=\"minicart\"]',\n            messagesSelector: '[data-placeholder=\"messages\"]',\n            productStatusSelector: '.stock.available',\n            addToCartButtonSelector: '.action.tocart',\n            addToCartButtonDisabledClass: 'disabled',\n            addToCartButtonTextWhileAdding: '',\n            addToCartButtonTextAdded: '',\n            addToCartButtonTextDefault: '',\n            productInfoResolver: productInfoResolver\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            if (this.options.bindSubmit) {\n                this._bindSubmit();\n            }\n            $(this.options.addToCartButtonSelector).prop('disabled', false);\n        },\n\n        /**\n         * @private\n         */\n        _bindSubmit: function () {\n            var self = this;\n\n            if (this.element.data('catalog-addtocart-initialized')) {\n                return;\n            }\n\n            this.element.data('catalog-addtocart-initialized', 1);\n            this.element.on('submit', function (e) {\n                e.preventDefault();\n                self.submitForm($(this));\n            });\n        },\n\n        /**\n         * @private\n         */\n        _redirect: function (url) {\n            var urlParts, locationParts, forceReload;\n\n            urlParts = url.split('#');\n            locationParts = window.location.href.split('#');\n            forceReload = urlParts[0] === locationParts[0];\n\n            window.location.assign(url);\n\n            if (forceReload) {\n                window.location.reload();\n            }\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isLoaderEnabled: function () {\n            return this.options.processStart && this.options.processStop;\n        },\n\n        /**\n         * Handler for the form 'submit' event\n         *\n         * @param {jQuery} form\n         */\n        submitForm: function (form) {\n            this.ajaxSubmit(form);\n        },\n\n        /**\n         * @param {jQuery} form\n         */\n        ajaxSubmit: function (form) {\n            var self = this,\n                productIds = idsResolver(form),\n                productInfo = self.options.productInfoResolver(form),\n                formData;\n\n            $(self.options.minicartSelector).trigger('contentLoading');\n            self.disableAddToCartButton(form);\n            formData = new FormData(form[0]);\n\n            $.ajax({\n                url: form.prop('action'),\n                data: formData,\n                type: 'post',\n                dataType: 'json',\n                cache: false,\n                contentType: false,\n                processData: false,\n\n                /** @inheritdoc */\n                beforeSend: function () {\n                    if (self.isLoaderEnabled()) {\n                        $('body').trigger(self.options.processStart);\n                    }\n                },\n\n                /** @inheritdoc */\n                success: function (res) {\n                    var eventData, parameters;\n\n                    $(document).trigger('ajax:addToCart', {\n                        'sku': form.data().productSku,\n                        'productIds': productIds,\n                        'productInfo': productInfo,\n                        'form': form,\n                        'response': res\n                    });\n\n                    if (self.isLoaderEnabled()) {\n                        $('body').trigger(self.options.processStop);\n                    }\n\n                    if (res.backUrl) {\n                        eventData = {\n                            'form': form,\n                            'redirectParameters': []\n                        };\n                        // trigger global event, so other modules will be able add parameters to redirect url\n                        $('body').trigger('catalogCategoryAddToCartRedirect', eventData);\n\n                        if (eventData.redirectParameters.length > 0 &&\n                            window.location.href.split(/[?#]/)[0] === res.backUrl\n                        ) {\n                            parameters = res.backUrl.split('#');\n                            parameters.push(eventData.redirectParameters.join('&'));\n                            res.backUrl = parameters.join('#');\n                        }\n\n                        self._redirect(res.backUrl);\n\n                        return;\n                    }\n\n                    if (res.messages) {\n                        $(self.options.messagesSelector).html(res.messages);\n                    }\n\n                    if (res.minicart) {\n                        $(self.options.minicartSelector).replaceWith(res.minicart);\n                        $(self.options.minicartSelector).trigger('contentUpdated');\n                    }\n\n                    if (res.product && res.product.statusText) {\n                        $(self.options.productStatusSelector)\n                            .removeClass('available')\n                            .addClass('unavailable')\n                            .find('span')\n                            .html(res.product.statusText);\n                    }\n                    self.enableAddToCartButton(form);\n                },\n\n                /** @inheritdoc */\n                error: function (res) {\n                    $(document).trigger('ajax:addToCart:error', {\n                        'sku': form.data().productSku,\n                        'productIds': productIds,\n                        'productInfo': productInfo,\n                        'form': form,\n                        'response': res\n                    });\n                },\n\n                /** @inheritdoc */\n                complete: function (res) {\n                    if (res.state() === 'rejected') {\n                        location.reload();\n                    }\n                }\n            });\n        },\n\n        /**\n         * @param {String} form\n         */\n        disableAddToCartButton: function (form) {\n            var addToCartButtonTextWhileAdding = this.options.addToCartButtonTextWhileAdding || $t('Adding...'),\n                addToCartButton = $(form).find(this.options.addToCartButtonSelector);\n\n            addToCartButton.addClass(this.options.addToCartButtonDisabledClass);\n            addToCartButton.find('span').text(addToCartButtonTextWhileAdding);\n            addToCartButton.prop('title', addToCartButtonTextWhileAdding);\n        },\n\n        /**\n         * @param {String} form\n         */\n        enableAddToCartButton: function (form) {\n            var addToCartButtonTextAdded = this.options.addToCartButtonTextAdded || $t('Added'),\n                self = this,\n                addToCartButton = $(form).find(this.options.addToCartButtonSelector);\n\n            addToCartButton.find('span').text(addToCartButtonTextAdded);\n            addToCartButton.prop('title', addToCartButtonTextAdded);\n\n            setTimeout(function () {\n                var addToCartButtonTextDefault = self.options.addToCartButtonTextDefault || $t('Add to Cart');\n\n                addToCartButton.removeClass(self.options.addToCartButtonDisabledClass);\n                addToCartButton.find('span').text(addToCartButtonTextDefault);\n                addToCartButton.prop('title', addToCartButtonTextDefault);\n            }, 1000);\n        }\n    });\n\n    return $.mage.catalogAddToCart;\n});\n","Magento_Catalog/js/storage-manager.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiElement',\n    'mageUtils',\n    'Magento_Catalog/js/product/storage/storage-service',\n    'Magento_Customer/js/section-config',\n    'jquery'\n], function (_, Element, utils, storage, sectionConfig, $) {\n    'use strict';\n\n    /**\n     * Flush events, that are clones of the same customer data sections\n     * Events listener\n     */\n    $(document).on('submit', function (event) {\n        var sections;\n\n        if (event.target.method.match(/post|put|delete/i)) {\n            sections = sectionConfig.getAffectedSections(event.target.action);\n\n            if (sections && window.localStorage) {\n                _.each(sections, function (section) {\n                    window.localStorage.removeItem(section);\n                });\n            }\n        }\n    });\n\n    return Element.extend({\n        defaults: {\n            defaultNamespace: {\n                lifetime: 1000\n            },\n            storagesConfiguration: {\n                'recently_viewed_product': {\n                    namespace: 'recently_viewed_product',\n                    className: 'IdsStorage',\n                    lifetime: '${ $.defaultNamespace.lifetime }',\n                    requestConfig: {\n                        typeId: '${ $.storagesConfiguration.recently_viewed_product.namespace }'\n                    },\n                    savePrevious: {\n                        namespace: '${ $.storagesConfiguration.recently_viewed_product.namespace }' + '_previous',\n                        className: '${ $.storagesConfiguration.recently_viewed_product.className }'\n                    },\n                    allowToSendRequest: 0\n                },\n                'recently_compared_product': {\n                    namespace: 'recently_compared_product',\n                    className: 'IdsStorageCompare',\n                    provider: 'compare-products',\n                    lifetime: '${ $.defaultNamespace.lifetime }',\n                    requestConfig: {\n                        typeId: '${ $.storagesConfiguration.recently_compared_product.namespace }'\n                    },\n                    savePrevious: {\n                        namespace: '${ $.storagesConfiguration.recently_compared_product.namespace }' + '_previous',\n                        className: '${ $.storagesConfiguration.recently_compared_product.className }'\n                    },\n                    allowToSendRequest: 0\n                },\n                'product_data_storage': {\n                    namespace: 'product_data_storage',\n                    className: 'DataStorage',\n                    allowToSendRequest: 0,\n                    updateRequestConfig: {\n                        url: '',\n                        method: 'GET',\n                        dataType: 'json'\n                    }\n                }\n            },\n            requestConfig: {\n                method: 'POST',\n                dataType: 'json',\n                ajaxSaveType: 'default',\n                ignoreProcessEvents: true\n            },\n            requestSent: 0\n        },\n\n        /**\n         * Initializes provider component.\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .prepareStoragesConfig()\n                .initStorages()\n                .initStartData()\n                .initUpdateStorageDataListener();\n\n            return this;\n        },\n\n        /**\n         * Initializes storages.\n         *\n         * @returns {Object} Chainable.\n         */\n        initStorages: function () {\n            _.each(this.storagesNamespace, function (name) {\n                this[name] = storage.createStorage(this.storagesConfiguration[name]);\n\n                if (this.storagesConfiguration[name].savePrevious) {\n                    this[name].previous = storage.createStorage(this.storagesConfiguration[name].savePrevious);\n                }\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Initializes start data.\n         *\n         * @returns {Object} Chainable.\n         */\n        initStartData: function () {\n            _.each(this.storagesNamespace, function (name) {\n                this.updateDataHandler(name, this[name].get());\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Prepare storages congfig.\n         *\n         * @returns {Object} Chainable.\n         */\n        prepareStoragesConfig: function () {\n            this.storagesNamespace = _.keys(this.storagesConfiguration);\n\n            _.each(this.storagesNamespace, function (name) {\n                this.storagesConfiguration[name].requestConfig = _.extend(\n                    utils.copy(this.requestConfig),\n                    this.storagesConfiguration[name].requestConfig\n                );\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Prepare date in UTC format (in GMT), and calculate unix timestamp based in seconds\n         *\n         * @returns {Number}\n         * @private\n         */\n        getUtcTime: function () {\n            return new Date().getTime() / 1000;\n        },\n\n        /**\n         * Initializes listeners to storages \"data\" property.\n         */\n        initUpdateStorageDataListener: function () {\n            _.each(this.storagesNamespace, function (name) {\n                if (this[name].data) {\n                    this[name].data.subscribe(this.updateDataHandler.bind(this, name));\n                }\n            }.bind(this));\n        },\n\n        /**\n         * Handlers for storages \"data\" property\n         */\n        updateDataHandler: function (name, data) {\n            var previousData = this[name].previous ? this[name].previous.get() : false;\n\n            if (!_.isEmpty(previousData) &&\n                !_.isEmpty(data) &&\n                !utils.compare(data, previousData).equal) {\n                this[name].set(data);\n                this[name].previous.set(data);\n                this.sendRequest(name, data);\n            } else if (\n                _.isEmpty(previousData) &&\n                !_.isEmpty(data)\n            ) {\n                this[name].set(data);\n                this.sendRequest(name, data);\n            }\n        },\n\n        /**\n         * Gets last updated time\n         *\n         * @param {String} name - storage name\n         */\n        getLastUpdate: function (name) {\n            return window.localStorage.getItem(this[name].namespace + '_last_update');\n        },\n\n        /**\n         * Sets last updated time\n         *\n         * @param {String} name - storage name\n         */\n        setLastUpdate: function (name) {\n            window.localStorage.setItem(this[name].namespace + '_last_update', this.getUtcTime());\n        },\n\n        /**\n         * Request handler\n         *\n         * @param {String} name - storage name\n         */\n        requestHandler: function (name) {\n            this.setLastUpdate(name);\n            this.requestSent = 1;\n        },\n\n        /**\n         * Sends request to server to gets data\n         *\n         * @param {String} name - storage name\n         * @param {Object} data - ids\n         */\n        sendRequest: function (name, data) {\n            var params  = utils.copy(this.storagesConfiguration[name].requestConfig),\n                url = params.syncUrl,\n                typeId = params.typeId;\n\n            if (this.requestSent || !~~this.storagesConfiguration[name].allowToSendRequest) {\n                return;\n            }\n\n            delete params.typeId;\n            delete params.url;\n            this.requestSent = 1;\n\n            return utils.ajaxSubmit({\n                url: url,\n                data: {\n                    ids: data,\n                    'type_id': typeId\n                }\n            }, params).done(this.requestHandler.bind(this, name));\n        }\n    });\n});\n","Magento_Catalog/js/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.compareList', {\n\n        /** @inheritdoc */\n        _create: function () {\n            var elem = this.element,\n                products = $('thead td', elem),\n                headings;\n\n            if (products.length > this.options.productsInRow) {\n                headings = $('<table></table>')\n                    .addClass('comparison headings data table')\n                    .insertBefore(elem.closest('.container'));\n\n                elem.addClass('scroll');\n\n                $('th', elem).each(function () {\n                    var th = $(this),\n                        thCopy = th.clone();\n\n                    th.animate({\n                        top: '+=0'\n                    }, 50, function () {\n                        var height = th.height();\n\n                        thCopy.css('height', height)\n                            .appendTo(headings)\n                            .wrap('<tr></tr>');\n                    });\n                });\n            }\n\n            $(this.options.windowPrintSelector).on('click', function (e) {\n                e.preventDefault();\n                window.print();\n            });\n        }\n    });\n\n    return $.mage.compareList;\n});\n","Magento_Catalog/js/jquery.zoom.min.js":"/*!\n    Zoom 1.7.14\n    license: MIT\n    http://www.jacklmoore.com/zoom\n*/\n(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery'\n        ], factory);\n    } else {\n        factory(window.jQuery);\n    }\n}(function ($) {\n    'use strict';\n    var defaults = {\n        url: false,\n        callback: false,\n        target: false,\n        duration: 120,\n        on: 'mouseover', // other options: grab, click, toggle\n        touch: true, // enables a touch fallback\n        onZoomIn: false,\n        onZoomOut: false,\n        magnify: 1\n    };\n\n    // Core Zoom Logic, independent of event listeners.\n    $.zoom = function(target, source, img, magnify) {\n        var targetHeight,\n            targetWidth,\n            sourceHeight,\n            sourceWidth,\n            xRatio,\n            yRatio,\n            offset,\n            $target = $(target),\n            position = $target.css('position'),\n            $source = $(source);\n\n        // The parent element needs positioning so that the zoomed element can be correctly positioned within.\n        $target.css('position', /(absolute|fixed)/.test(position) ? position : 'relative');\n        $target.css('overflow', 'hidden');\n\n        img.style.width = img.style.height = '';\n\n        if($(target).children(\"img.zoomImg\").length == 0)\n        $(img)\n            .addClass('zoomImg')\n            .css({\n                position: 'absolute',\n                top: 0,\n                left: 0,\n                opacity: 0,\n                width: img.width * magnify,\n                height: img.height * magnify,\n                border: 'none',\n                maxWidth: 'none',\n                maxHeight: 'none'\n            })\n            .appendTo(target);\n\n        return {\n            init: function() {\n                targetWidth = $target.outerWidth();\n                targetHeight = $target.outerHeight();\n\n                if (source === $target[0]) {\n                    sourceWidth = targetWidth;\n                    sourceHeight = targetHeight;\n                } else {\n                    sourceWidth = $source.outerWidth();\n                    sourceHeight = $source.outerHeight();\n                }\n\n                xRatio = (img.width - targetWidth) / sourceWidth;\n                yRatio = (img.height - targetHeight) / sourceHeight;\n\n                offset = $source.offset();\n            },\n            move: function (e) {\n                var left = (e.pageX - offset.left),\n                    top = (e.pageY - offset.top);\n\n                top = Math.max(Math.min(top, sourceHeight), 0);\n                left = Math.max(Math.min(left, sourceWidth), 0);\n\n                img.style.left = (left * -xRatio) + 'px';\n                img.style.top = (top * -yRatio) + 'px';\n            }\n        };\n    };\n\n    $.fn.zoom = function (options) {\n        return this.each(function () {\n            var\n            settings = $.extend({}, defaults, options || {}),\n            //target will display the zoomed image\n            target = settings.target || this,\n            //source will provide zoom location info (thumbnail)\n            source = this,\n            $source = $(source),\n            $target = $(target),\n            img = document.createElement('img'),\n            $img = $(img),\n            mousemove = 'mousemove.zoom',\n            clicked = false,\n            touched = false,\n            $urlElement;\n\n            // If a url wasn't specified, look for an image element.\n            if (!settings.url) {\n                $urlElement = $source.find('img');\n                if ($urlElement[0]) {\n                    settings.url = $urlElement.data('src') || $urlElement.attr('src');\n                }\n                if (!settings.url) {\n                    return;\n                }\n            }\n\n            (function(){\n                var position = $target.css('position');\n                var overflow = $target.css('overflow');\n\n                $source.one('zoom.destroy', function(){\n                    $source.off(\".zoom\");\n                    $target.css('position', position);\n                    $target.css('overflow', overflow);\n                    $img.remove();\n                });\n                \n            }());\n\n            img.onload = function () {\n                var zoom = $.zoom(target, source, img, settings.magnify);\n\n                function start(e) {\n                    zoom.init();\n                    zoom.move(e);\n\n                    // Skip the fade-in for IE8 and lower since it chokes on fading-in\n                    // and changing position based on mousemovement at the same time.\n                    $img.stop()\n                    .fadeTo($.support.opacity ? settings.duration : 0, 1, $.isFunction(settings.onZoomIn) ? settings.onZoomIn.call(img) : false);\n                }\n\n                function stop() {\n                    $img.stop()\n                    .fadeTo(settings.duration, 0, $.isFunction(settings.onZoomOut) ? settings.onZoomOut.call(img) : false);\n                }\n\n                // Mouse events\n                if (settings.on === 'grab') {\n                    $source\n                        .on('mousedown.zoom',\n                            function (e) {\n                                if (e.which === 1) {\n                                    $(document).one('mouseup.zoom',\n                                        function () {\n                                            stop();\n\n                                            $(document).off(mousemove, zoom.move);\n                                        }\n                                    );\n\n                                    start(e);\n\n                                    $(document).on(mousemove, zoom.move);\n\n                                    e.preventDefault();\n                                }\n                            }\n                        );\n                } else if (settings.on === 'click') {\n                    $source.on('click.zoom',\n                        function (e) {\n                            if (clicked) {\n                                // bubble the event up to the document to trigger the unbind.\n                                return;\n                            } else {\n                                clicked = true;\n                                start(e);\n                                $(document).on(mousemove, zoom.move);\n                                $(document).one('click.zoom',\n                                    function () {\n                                        stop();\n                                        clicked = false;\n                                        $(document).off(mousemove, zoom.move);\n                                    }\n                                );\n                                return false;\n                            }\n                        }\n                    );\n                } else if (settings.on === 'toggle') {\n                    $source.on('click.zoom',\n                        function (e) {\n                            if (clicked) {\n                                stop();\n                            } else {\n                                start(e);\n                            }\n                            clicked = !clicked;\n                        }\n                    );\n                } else if (settings.on === 'mouseover') {\n                    zoom.init(); // Preemptively call init because IE7 will fire the mousemove handler before the hover handler.\n\n                    $source\n                        .on('mouseenter.zoom', start)\n                        .on('mouseleave.zoom', stop)\n                        .on(mousemove, zoom.move);\n                }\n\n                // Touch fallback\n                if (settings.touch) {\n                    $source\n                        .on('touchstart.zoom', function (e) {\n                            e.preventDefault();\n                            if (touched) {\n                                touched = false;\n                                stop();\n                            } else {\n                                touched = true;\n                                start( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );\n                            }\n                        })\n                        .on('touchmove.zoom', function (e) {\n                            e.preventDefault();\n                            zoom.move( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );\n                        });\n                }\n                \n                if ($.isFunction(settings.callback)) {\n                    settings.callback.call(img);\n                }\n            };\n\n            img.src = settings.url;\n        });\n    };\n\n    $.fn.zoom.defaults = defaults;\n}));\n","Magento_Catalog/js/product/name.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/list/column-status-validator',\n    'escaper'\n], function (Column, columnStatusValidator, escaper) {\n    'use strict';\n\n    return Column.extend({\n        defaults: {\n            allowedTags: ['div', 'span', 'b', 'strong', 'i', 'em', 'u', 'a']\n        },\n\n        /**\n         * Depends on this option, product name can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'name', 'show_attributes');\n        },\n\n        /**\n         * Name column.\n         *\n         * @param {String} label\n         * @returns {String}\n         */\n        getNameUnsanitizedHtml: function (label) {\n            return escaper.escapeHtml(label, this.allowedTags);\n        }\n    });\n});\n","Magento_Catalog/js/product/addtocart-button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/uenc-processor',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Element, uencProcessor, columnStatusValidator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            label: ''\n        },\n\n        /**\n         * Prepare data, that will be inserted as data-mage-init attribute into button. With help of this attribute\n         * Add To * buttons can understand post data and urls\n         *\n         * @param {Object} row\n         * @returns {String}\n         */\n        getDataMageInit: function (row) {\n            return '{\"redirectUrl\": { \"url\" : \"'  + uencProcessor(row['add_to_cart_button'].url) + '\"}}';\n        },\n\n        /**\n         * Prepare Data-Post data that will be used in data-mage-init\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getDataPost: function (row) {\n            return uencProcessor(row['add_to_cart_button']['post_data']);\n        },\n\n        /**\n         * Check if product has required options.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        hasRequiredOptions: function (row) {\n            return row['add_to_cart_button']['required_options'];\n        },\n\n        /**\n         * Depends on this option, \"Add to cart\" button can be shown or hide\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        isSalable: function (row) {\n            return row['is_salable'];\n        },\n\n        /**\n         * Depends on this option, stock status text can be \"In stock\" or \"Out Of Stock\"\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        isAvailable: function (row) {\n            return row['is_available'];\n        },\n\n        /**\n         * Depends on this option, \"Add to cart\" button can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'add_to_cart', 'show_buttons');\n        },\n\n        /**\n         * Get button label.\n         *\n         * @return {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/addtocompare-button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/uenc-processor',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Column, uencProcessor, columnStatusValidator) {\n    'use strict';\n\n    return Column.extend({\n        defaults: {\n            label: ''\n        },\n\n        /**\n         * Prepare Data-Post data that will be used in data-mage-init\n         *\n         * @param {Object} row\n         * @returns {Array}\n         */\n        getDataPost: function (row) {\n            return uencProcessor(row['add_to_compare_button'].url ||\n                    row['add_to_compare_button']['post_data']);\n        },\n\n        /**\n         * Depends on this option, \"Add to compare\" button can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'add_to_compare', 'show_buttons');\n        },\n\n        /**\n         * Get button label.\n         *\n         * @return {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/learn-more.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Column, columnStatusValidator) {\n    'use strict';\n\n    return Column.extend({\n        /**\n         * Depends on this option, \"Learn More\" link can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'learn_more', 'show_attributes');\n        }\n    });\n});\n","Magento_Catalog/js/product/remaining-characters.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/translate',\n    'jquery-ui-modules/widget'\n], function ($, $t) {\n    'use strict';\n\n    $.widget('mage.remainingCharacters', {\n        options: {\n            remainingText: $t('remaining'),\n            tooManyText: $t('too many'),\n            errorClass: 'mage-error',\n            noDisplayClass: 'no-display'\n        },\n\n        /**\n         * Initializes custom option component\n         *\n         * @private\n         */\n        _create: function () {\n            this.note = $(this.options.noteSelector);\n            this.counter = $(this.options.counterSelector);\n\n            this.updateCharacterCount();\n            this.element.on('change keyup paste', this.updateCharacterCount.bind(this));\n        },\n\n        /**\n         * Updates counter message\n         */\n        updateCharacterCount: function () {\n            var length = this.element.val().length,\n                diff = this.options.maxLength - length;\n\n            this.counter.text(this._formatMessage(diff));\n            this.counter.toggleClass(this.options.noDisplayClass, length === 0);\n            this.note.toggleClass(this.options.errorClass, diff < 0);\n        },\n\n        /**\n         * Format remaining characters message\n         *\n         * @param {int} diff\n         * @returns {String}\n         * @private\n         */\n        _formatMessage: function (diff) {\n            var count = Math.abs(diff),\n                qualifier = diff < 0 ? this.options.tooManyText : this.options.remainingText;\n\n            return '(' + count + ' ' + qualifier + ')';\n        }\n    });\n\n    return $.mage.remainingCharacters;\n});\n","Magento_Catalog/js/product/query-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n        'underscore'\n    ], function (_) {\n        'use strict';\n\n        return {\n\n            /**\n             * Build query to get id\n             *\n             * @param {Object} data\n             */\n            buildQuery: function (data) {\n                var filters = [];\n\n                _.each(data, function (value, key) {\n                    filters.push({\n                        field: key,\n                        value: value,\n                        'condition_type': 'in'\n                    });\n                });\n\n                return {\n                    searchCriteria: {\n                        filterGroups: [\n                            {\n                                filters: filters\n                            }\n                        ]\n                    }\n                };\n            }\n        };\n    }\n);\n","Magento_Catalog/js/product/provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'uiElement',\n    'Magento_Catalog/js/product/storage/storage-service',\n    'Magento_Customer/js/customer-data',\n    'Magento_Catalog/js/product/view/product-ids-resolver'\n], function (_, $, utils, Element, storage, customerData, productResolver) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            identifiersConfig: {\n                namespace: ''\n            },\n            productStorageConfig: {\n                namespace: 'product_data_storage',\n                customerDataProvider: 'product_data_storage',\n                updateRequestConfig: {\n                    url: '',\n                    method: 'GET',\n                    dataType: 'json'\n                },\n                className: 'DataStorage'\n            },\n            ids: {},\n            listens: {\n                ids: 'idsHandler'\n            }\n        },\n\n        /**\n         * Initializes provider component.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initIdsStorage();\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super();\n            this.observe('ids');\n\n            return this;\n        },\n\n        /**\n         * Initializes ids storage.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initIdsStorage: function () {\n            storage.onStorageInit(this.identifiersConfig.namespace, this.idsStorageHandler.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Initializes ids storage handler.\n         *\n         * @param {Object} idsStorage\n         */\n        idsStorageHandler: function (idsStorage) {\n            this.idsStorage = idsStorage;\n            this.productStorage = storage.createStorage(this.productStorageConfig);\n            this.productStorage.data.subscribe(this.dataCollectionHandler.bind(this));\n\n            if (~~this.idsStorage.allowToSendRequest) {\n                customerData.reload([idsStorage.namespace]).done(this._resolveDataByIds.bind(this));\n            } else {\n                this._resolveDataByIds();\n            }\n        },\n\n        /**\n         * Callback, which load by ids from ids-storage product data\n         *\n         * @private\n         */\n        _resolveDataByIds: function () {\n            if (!window.checkout || !window.checkout.baseUrl) {\n                // We need data that the minicart provdes to determine storeId/websiteId\n                return;\n            }\n\n            this.initIdsListener();\n            this.idsMerger(\n                this.idsStorage.get(),\n                this.prepareDataFromCustomerData(customerData.get(this.identifiersConfig.namespace)())\n            );\n\n            if (!_.isEmpty(this.productStorage.data())) {\n                this.dataCollectionHandler(this.productStorage.data());\n            } else {\n                this.productStorage.setIds(this.data.currency, this.data.store, this.ids());\n            }\n        },\n\n        /**\n         * Init ids storage listener.\n         */\n        initIdsListener: function () {\n            customerData.get(this.identifiersConfig.namespace).subscribe(function (data) {\n                this.idsMerger(this.prepareDataFromCustomerData(data));\n            }.bind(this));\n            this.idsStorage.data.subscribe(this.idsMerger.bind(this));\n        },\n\n        /**\n         * Prepare data from customerData.\n         *\n         * @param {Object} data\n         *\n         * @returns {Object}\n         */\n        prepareDataFromCustomerData: function (data) {\n            data = data.items ? data.items : data;\n\n            return data;\n        },\n\n        /**\n         * Filter ids by their lifetime in order to show only hot ids :)\n         *\n         * @param {Object} ids\n         * @returns {Array}\n         */\n        filterIds: function (ids) {\n            var _ids = {},\n                currentTime = new Date().getTime() / 1000,\n                currentProductIds = productResolver($('#product_addtocart_form')),\n                productCurrentScope = this.data.productCurrentScope,\n                scopeId = productCurrentScope === 'store' ? window.checkout.storeId :\n                productCurrentScope === 'group' ? window.checkout.storeGroupId :\n                    window.checkout.websiteId;\n\n            _.each(ids, function (id, key) {\n                if (\n                    currentTime - ids[key]['added_at'] < ~~this.idsStorage.lifetime &&\n                    !_.contains(currentProductIds, ids[key]['product_id']) &&\n                    (!id.hasOwnProperty('scope_id') || ids[key]['scope_id'] === scopeId)\n                ) {\n                    _ids[id['product_id']] = id;\n\n                }\n            }, this);\n\n            return _ids;\n        },\n\n        /**\n         * Merges id from storage and customer data\n         *\n         * @param {Object} data\n         * @param {Object} optionalData\n         */\n        idsMerger: function (data, optionalData) {\n            if (data && optionalData) {\n                data = _.extend(data, optionalData);\n            }\n\n            if (!_.isEmpty(data)) {\n                this.ids(\n                    this.filterIds(_.extend(this.ids(), data))\n                );\n            }\n        },\n\n        /**\n         * Ids update handler\n         *\n         * @param {Object} data\n         */\n        idsHandler: function (data) {\n            this.productStorage.setIds(this.data.currency, this.data.store, data);\n        },\n\n        /**\n         * Process data\n         *\n         * @param {Object} data\n         */\n        processData: function (data) {\n            var curData = utils.copy(this.data),\n                ids = this.ids();\n\n            delete data['data_id'];\n            data = _.values(data);\n\n            _.each(data, function (record, index) {\n                record._rowIndex = index;\n                record['added_at'] = ids[record.id]['added_at'];\n            }, this);\n\n            curData.items = data;\n            this.set('data', curData);\n        },\n\n        /**\n         * Product storage data handler\n         *\n         * @param {Object} data\n         */\n        dataCollectionHandler: function (data) {\n            data = this.filterData(data);\n            this.processData(data);\n        },\n\n        /**\n         * Filters data from product storage by ids\n         *\n         * @param {Object} data\n         *\n         * @returns {Object}\n         */\n        filterData: function (data) {\n            var result = {},\n                i = 0,\n                ids = _.keys(this.ids()),\n                length = ids.length;\n\n            for (i; i < length; i++) {\n                if (ids[i] && data[ids[i]]) {\n                    result[ids[i]] = data[ids[i]];\n                }\n            }\n\n            return result;\n        }\n    });\n});\n","Magento_Catalog/js/product/provider-compared.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    './provider',\n    'Magento_Catalog/js/product/storage/storage-service',\n    'Magento_Customer/js/customer-data'\n], function (_, Provider, storage, customerData) {\n    'use strict';\n\n    return Provider.extend({\n\n        /**\n         * Ids update handler\n         *\n         * @param {Object} data\n         */\n        idsHandler: function (data) {\n            this.productStorage.setIds(this.data.currency, this.data.store, this.dataFilter(data));\n        },\n\n        /**\n         * Filters data by provider\n         *\n         * @param {Object} data\n         *\n         * @returns {Object}\n         */\n        dataFilter: function (data) {\n            var providerData = this.idsStorage.prepareData(customerData.get(this.identifiersConfig.provider)().items),\n                result = {},\n                productCurrentScope,\n                scopeId;\n\n            if (typeof this.data.productCurrentScope !== 'undefined' && window.checkout && window.checkout.baseUrl) {\n                productCurrentScope = this.data.productCurrentScope;\n                scopeId = productCurrentScope === 'store' ? window.checkout.storeId :\n                    productCurrentScope === 'group' ? window.checkout.storeGroupId :\n                        window.checkout.websiteId;\n                _.each(data, function (value, key) {\n                    if (!providerData[productCurrentScope + '-' + scopeId + '-' + key]) {\n                        result[key] = value;\n                    }\n                });\n            } else {\n                _.each(data, function (value, key) {\n                    if (!providerData[key]) {\n                        result[key] = value;\n                    }\n                });\n            }\n\n            return result;\n        },\n\n        /**\n         * Filters data from product storage by ids\n         *\n         * @param {Object} data\n         *\n         * @returns {Object}\n         */\n        filterData: function (data) {\n            var result = {},\n                i = 0,\n                ids = _.keys(this.dataFilter(this.ids())),\n                length = ids.length;\n\n            for (i; i < length; i++) {\n                if (ids[i] && data[ids[i]]) {\n                    result[ids[i]] = data[ids[i]];\n                }\n            }\n\n            return result;\n        }\n    });\n});\n","Magento_Catalog/js/product/breadcrumbs.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Theme/js/model/breadcrumb-list'\n], function ($, breadcrumbList) {\n    'use strict';\n\n    return function (widget) {\n\n        $.widget('mage.breadcrumbs', widget, {\n            options: {\n                categoryUrlSuffix: '',\n                useCategoryPathInUrl: false,\n                product: '',\n                categoryItemSelector: '.category-item',\n                menuContainer: '[data-action=\"navigation\"] > ul'\n            },\n\n            /** @inheritdoc */\n            _render: function () {\n                this._appendCatalogCrumbs();\n                this._super();\n            },\n\n            /**\n             * Append category and product crumbs.\n             *\n             * @private\n             */\n            _appendCatalogCrumbs: function () {\n                var categoryCrumbs = this._resolveCategoryCrumbs();\n\n                categoryCrumbs.forEach(function (crumbInfo) {\n                    breadcrumbList.push(crumbInfo);\n                });\n\n                if (this.options.product) {\n                    breadcrumbList.push(this._getProductCrumb());\n                }\n            },\n\n            /**\n             * Resolve categories crumbs.\n             *\n             * @return Array\n             * @private\n             */\n            _resolveCategoryCrumbs: function () {\n                var menuItem = this._resolveCategoryMenuItem(),\n                    categoryCrumbs = [];\n\n                if (menuItem !== null && menuItem.length) {\n                    categoryCrumbs.unshift(this._getCategoryCrumb(menuItem));\n\n                    while ((menuItem = this._getParentMenuItem(menuItem)) !== null) {\n                        categoryCrumbs.unshift(this._getCategoryCrumb(menuItem));\n                    }\n                }\n\n                return categoryCrumbs;\n            },\n\n            /**\n             * Returns crumb data.\n             *\n             * @param {Object} menuItem\n             * @return {Object}\n             * @private\n             */\n            _getCategoryCrumb: function (menuItem) {\n                return {\n                    'name': 'category',\n                    'label': menuItem.text(),\n                    'link': menuItem.attr('href'),\n                    'title': ''\n                };\n            },\n\n            /**\n             * Returns product crumb.\n             *\n             * @return {Object}\n             * @private\n             */\n            _getProductCrumb: function () {\n                return {\n                    'name': 'product',\n                    'label': this.options.product,\n                    'link': '',\n                    'title': ''\n                };\n            },\n\n            /**\n             * Find parent menu item for current.\n             *\n             * @param {Object} menuItem\n             * @return {Object|null}\n             * @private\n             */\n            _getParentMenuItem: function (menuItem) {\n                var classes,\n                    classNav,\n                    parentClass,\n                    parentMenuItem = null;\n\n                if (!menuItem) {\n                    return null;\n                }\n\n                classes = menuItem.parent().attr('class');\n                classNav = classes.match(/(nav\\-)[0-9]+(\\-[0-9]+)+/gi);\n\n                if (classNav) {\n                    classNav = classNav[0];\n                    parentClass = classNav.substr(0, classNav.lastIndexOf('-'));\n\n                    if (parentClass.lastIndexOf('-') !== -1) {\n                        parentMenuItem = $(this.options.menuContainer).find('.' + parentClass + ' > a');\n                        parentMenuItem = parentMenuItem.length ? parentMenuItem : null;\n                    }\n                }\n\n                return parentMenuItem;\n            },\n\n            /**\n             * Returns category menu item.\n             *\n             * Tries to resolve category from url or from referrer as fallback and\n             * find menu item from navigation menu by category url.\n             *\n             * @return {Object|null}\n             * @private\n             */\n            _resolveCategoryMenuItem: function () {\n                var categoryUrl = this._resolveCategoryUrl(),\n                    menu = $(this.options.menuContainer),\n                    categoryMenuItem = null;\n\n                if (categoryUrl && menu.length) {\n                    categoryMenuItem = menu.find(\n                        this.options.categoryItemSelector +\n                        ' > a[href=\"' + categoryUrl + '\"]'\n                    );\n                }\n\n                return categoryMenuItem;\n            },\n\n            /**\n             * Returns category url.\n             *\n             * @return {String}\n             * @private\n             */\n            _resolveCategoryUrl: function () {\n                var categoryUrl;\n\n                if (this.options.useCategoryPathInUrl) {\n                    // In case category path is used in product url - resolve category url from current url.\n                    categoryUrl = window.location.href.split('?')[0];\n                    categoryUrl = categoryUrl.substring(0, categoryUrl.lastIndexOf('/')) +\n                        this.options.categoryUrlSuffix;\n                } else {\n                    // In other case - try to resolve it from referrer (without parameters).\n                    categoryUrl = document.referrer;\n\n                    if (categoryUrl.indexOf('?') > 0) {\n                        categoryUrl = categoryUrl.substr(0, categoryUrl.indexOf('?'));\n                    }\n                }\n\n                return categoryUrl;\n            }\n        });\n\n        return $.mage.breadcrumbs;\n    };\n});\n","Magento_Catalog/js/product/uenc-processor.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([], function () {\n        'use strict';\n\n        /**\n         * Check data to JSON.\n         *\n         * @returns {Boolean}\n         */\n        function _isJSON(data) {\n            try {\n                JSON.parse(data);\n            } catch (e) {\n                return false;\n            }\n\n            return true;\n        }\n\n        /**\n         * Processes data.\n         *\n         * @param {Object} data\n         * @param {String} placeholder\n         * @param {String} uenc\n         *\n         * @returns {String}\n         */\n        function _stringProcessor(data, placeholder, uenc) {\n            if (data && ~data.indexOf(placeholder)) {\n                return data.replace(placeholder, uenc);\n            }\n\n            return data;\n        }\n\n        /**\n         * Processes data.\n         *\n         * @param {Object} data\n         * @param {String} placeholder\n         * @param {String} uenc\n         *\n         * @returns {String}\n         */\n        function _objectProcessor(data, placeholder, uenc) {\n            data = JSON.parse(data);\n\n            if (data.hasOwnProperty('action')) {\n                data.action = _stringProcessor(data.action, placeholder, uenc);\n            }\n\n            if (data.hasOwnProperty('data') && data.data.hasOwnProperty('uenc')) {\n                data.data.uenc = uenc;\n            }\n\n            return JSON.stringify(data);\n        }\n\n        /**\n         * Processes data.\n         *\n         * @param {Object} data\n         * @param {String} placeholder\n         *\n         * @returns {String}\n         */\n        return function (data, placeholder) {\n            var uenc = btoa(window.location.href).replace('+/=', '-_,');\n\n            placeholder = placeholder || encodeURI('%uenc%');\n\n            return _isJSON(data) ?\n                _objectProcessor(data, placeholder, uenc) :\n                _stringProcessor(data, placeholder, uenc);\n\n        };\n    }\n);\n","Magento_Catalog/js/product/list/column-status-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    return _.extend({\n        /**\n         * Check whether we can show column depends on server settings or not\n         *\n         * @param {Object} source\n         * @param {String} attributeCode\n         * @param {String} type\n         * @returns {Boolean}\n         */\n        isValid: function (source, attributeCode, type) {\n            var attributes;\n\n            if (!source[type]) {\n                return false;\n            }\n\n            attributes = source[type].split(',');\n\n            return _.contains(attributes, attributeCode);\n        }\n    });\n});\n","Magento_Catalog/js/product/list/listing.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'Magento_Ui/js/grid/listing'\n], function (ko, _, Listing) {\n    'use strict';\n\n    return Listing.extend({\n        defaults: {\n            additionalClasses: '',\n            filteredRows: {},\n            limit: 5,\n            listens: {\n                elems: 'filterRowsFromCache',\n                '${ $.provider }:data.items': 'filterRowsFromServer'\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.filteredRows = ko.observable();\n            this.initProductsLimit();\n            this.hideLoader();\n        },\n\n        /**\n         * Initialize product limit\n         * Product limit can be configured through Ui component.\n         * Product limit are present in widget form\n         *\n         * @returns {exports}\n         */\n        initProductsLimit: function () {\n            if (this.source['page_size']) {\n                this.limit = this.source['page_size'];\n            }\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Listing} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track({\n                    rows: []\n                });\n\n            return this;\n        },\n\n        /**\n         * Sort and filter rows, that are already in magento storage cache\n         *\n         * @return void\n         */\n        filterRowsFromCache: function () {\n            this._filterRows(this.rows);\n        },\n\n        /**\n         * Sort and filter rows, that are come from backend\n         *\n         * @param {Object} rows\n         */\n        filterRowsFromServer: function (rows) {\n            this._filterRows(rows);\n        },\n\n        /**\n         * Filter rows by limit and sort them\n         *\n         * @param {Array} rows\n         * @private\n         */\n        _filterRows: function (rows) {\n            this.filteredRows(_.sortBy(rows, 'added_at').reverse().slice(0, this.limit));\n        },\n\n        /**\n         * Can retrieve product url\n         *\n         * @param {Object} row\n         * @returns {String}\n         */\n        getUrl: function (row) {\n            return row.url;\n        },\n\n        /**\n         * Get product attribute by code.\n         *\n         * @param {String} code\n         * @return {Object}\n         */\n        getComponentByCode: function (code) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                component;\n\n            component = _.filter(elems, function (elem) {\n                return elem.index === code;\n            }, this).pop();\n\n            return component;\n        }\n    });\n});\n","Magento_Catalog/js/product/list/toolbar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    /**\n     * ProductListToolbarForm Widget - this widget is setting cookie and submitting form according to toolbar controls\n     */\n    $.widget('mage.productListToolbarForm', {\n\n        options: {\n            modeControl: '[data-role=\"mode-switcher\"]',\n            directionControl: '[data-role=\"direction-switcher\"]',\n            orderControl: '[data-role=\"sorter\"]',\n            limitControl: '[data-role=\"limiter\"]',\n            mode: 'product_list_mode',\n            direction: 'product_list_dir',\n            order: 'product_list_order',\n            limit: 'product_list_limit',\n            page: 'p',\n            modeDefault: 'grid',\n            directionDefault: 'asc',\n            orderDefault: 'position',\n            limitDefault: '9',\n            url: '',\n            formKey: '',\n            post: false\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this._bind(\n                $(this.options.modeControl, this.element),\n                this.options.mode,\n                this.options.modeDefault\n            );\n            this._bind(\n                $(this.options.directionControl, this.element),\n                this.options.direction,\n                this.options.directionDefault\n            );\n            this._bind(\n                $(this.options.orderControl, this.element),\n                this.options.order,\n                this.options.orderDefault\n            );\n            this._bind(\n                $(this.options.limitControl, this.element),\n                this.options.limit,\n                this.options.limitDefault\n            );\n        },\n\n        /** @inheritdoc */\n        _bind: function (element, paramName, defaultValue) {\n            if (element.is('select')) {\n                element.on('change', {\n                    paramName: paramName,\n                    'default': defaultValue\n                }, $.proxy(this._processSelect, this));\n            } else {\n                element.on('click', {\n                    paramName: paramName,\n                    'default': defaultValue\n                }, $.proxy(this._processLink, this));\n            }\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _processLink: function (event) {\n            event.preventDefault();\n            this.changeUrl(\n                event.data.paramName,\n                $(event.currentTarget).data('value'),\n                event.data.default\n            );\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _processSelect: function (event) {\n            this.changeUrl(\n                event.data.paramName,\n                event.currentTarget.options[event.currentTarget.selectedIndex].value,\n                event.data.default\n            );\n        },\n\n        /**\n         * @private\n         */\n        getUrlParams: function () {\n            var decode = window.decodeURIComponent,\n                urlPaths = this.options.url.split('?'),\n                urlParams = urlPaths[1] ? urlPaths[1].split('&') : [],\n                params = {},\n                parameters, i;\n\n            for (i = 0; i < urlParams.length; i++) {\n                parameters = urlParams[i].split('=');\n                params[decode(parameters[0])] = parameters[1] !== undefined ?\n                    decode(parameters[1].replace(/\\+/g, '%20')) :\n                    '';\n            }\n\n            return params;\n        },\n\n        /**\n         * @returns {String}\n         * @private\n         */\n        getCurrentLimit: function () {\n            return this.getUrlParams()[this.options.limit] || this.options.limitDefault;\n        },\n\n        /**\n         * @returns {String}\n         * @private\n         */\n        getCurrentPage: function () {\n            return this.getUrlParams()[this.options.page] || 1;\n        },\n\n        /**\n         * @param {String} paramName\n         * @param {*} paramValue\n         * @param {*} defaultValue\n         */\n        changeUrl: function (paramName, paramValue, defaultValue) {\n            var urlPaths = this.options.url.split('?'),\n                baseUrl = urlPaths[0],\n                paramData = this.getUrlParams(),\n                currentPage = this.getCurrentPage(),\n                form, params, key, input, formKey, newPage;\n\n            if (currentPage > 1 && paramName === this.options.mode) {\n                delete paramData[this.options.page];\n            }\n\n            if (currentPage > 1 && paramName === this.options.limit) {\n                newPage = Math.floor(this.getCurrentLimit() * (currentPage - 1) / paramValue) + 1;\n\n                if (newPage > 1) {\n                    paramData[this.options.page] = newPage;\n                } else {\n                    delete paramData[this.options.page];\n                }\n            }\n\n            paramData[paramName] = paramValue;\n\n            if (this.options.post) {\n                form = document.createElement('form');\n                params = [this.options.mode, this.options.direction, this.options.order, this.options.limit];\n\n                for (key in paramData) {\n                    if (params.indexOf(key) !== -1) { //eslint-disable-line max-depth\n                        input = document.createElement('input');\n                        input.name = key;\n                        input.value = paramData[key];\n                        form.appendChild(input);\n                        delete paramData[key];\n                    }\n                }\n                formKey = document.createElement('input');\n                formKey.name = 'form_key';\n                formKey.value = this.options.formKey;\n                form.appendChild(formKey);\n\n                paramData = $.param(paramData);\n                baseUrl += paramData.length ? '?' + paramData : '';\n\n                form.action = baseUrl;\n                form.method = 'POST';\n                document.body.appendChild(form);\n                form.submit();\n            } else {\n                if (paramValue == defaultValue) { //eslint-disable-line eqeqeq\n                    delete paramData[paramName];\n                }\n\n                paramData = $.param(paramData);\n                location.href = baseUrl + (paramData.length ? '?' + paramData : '');\n            }\n        }\n    });\n\n    return $.mage.productListToolbarForm;\n});\n","Magento_Catalog/js/product/list/columns/image.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (_, Element, columnStatusValidator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            bodyTmpl: 'Magento_Catalog/product/list/columns/image',\n            imageCode: 'default',\n            image: {}\n        },\n\n        /**\n         * Find image by code in scope of images\n         *\n         * @param {Object} images\n         * @returns {*|T}\n         */\n        getImage: function (images) {\n            return _.filter(images, function (image) {\n                return this.imageCode === image.code;\n            }, this).pop();\n        },\n\n        /**\n         * Get image path.\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getImageUrl: function (row) {\n            return this.getImage(row.images).url;\n        },\n\n        /**\n         * Get image box width.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getWidth: function (row) {\n            return this.getImage(row.images).width;\n        },\n\n        /**\n         * Get image box height.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getHeight: function (row) {\n            return this.getImage(row.images).height;\n        },\n\n        /**\n         * Get resized image width.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getResizedImageWidth: function (row) {\n            return this.getImage(row.images)['resized_width'];\n        },\n\n        /**\n         * Get resized image height.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getResizedImageHeight: function (row) {\n            return this.getImage(row.images)['resized_height'];\n        },\n\n        /**\n         * Get image alt text.\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getLabel: function (row) {\n            if (!this.imageExists(row)) {\n                return this._super();\n            }\n\n            return this.getImage(row.images).label;\n        },\n\n        /**\n         * Check if image exist.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        imageExists: function (row) {\n            return this.getImage(row.images) !== 'undefined';\n        },\n\n        /**\n         * Check if component must be shown.\n         *\n         * @return {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'image', 'show_attributes');\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/pricetype-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'underscore',\n    'uiCollection'\n], function (ko, _, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        /**\n         * Find from all price ui components, price with specific code, init source on it and set priceType\n         *\n         * @param {String} code\n         * @returns {*|T}\n         */\n        getPriceByCode: function (code) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                price;\n\n            price = _.filter(elems, function (elem) {\n                return elem.index.split('.').shift() === code;\n            }, this).pop();\n\n            price.source = this.source();\n            price.priceType = code;\n\n            return price;\n        },\n\n        /**\n         * Retrieve body template\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Check whether price has price range, depends on different options, that can be choose\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        hasPriceRange: function (row) {\n            return row['price_info']['max_regular_price'] !== row['price_info']['min_regular_price'];\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/price-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiCollection',\n    'Magento_Catalog/js/product/list/column-status-validator',\n    'uiLayout'\n], function (ko, _, registry, utils, Collection, columnStatusValidator, layout) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            label: '',\n            hasSpecialPrice: false,\n            showMinimalPrice: false,\n            useLinkForAsLowAs: false,\n            visible: true,\n            headerTmpl: 'ui/grid/columns/text',\n            bodyTmpl: 'Magento_Catalog/product/price/price_box',\n            disableAction: false,\n            controlVisibility: true,\n            sortable: false,\n            sorting: false,\n            draggable: true,\n            fieldClass: {},\n            renders: {\n                default: {}\n            },\n            ignoreTmpls: {\n                fieldAction: true\n            },\n            statefull: {\n                visible: true,\n                sorting: true\n            },\n            imports: {\n                exportSorting: 'sorting'\n            },\n            listens: {\n                elems: ''\n            },\n            modules: {\n                source: '${ $.provider }'\n            },\n            pricesInit: {}\n        },\n\n        /**\n         * Sort prices api\n         *\n         * @returns {exports}\n         */\n        sort: function () {\n            return this;\n        },\n\n        /**\n         * Check whether is allowed to render price or not\n         *\n         * @returns {*}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'price', 'show_attributes');\n        },\n\n        /**\n         * Retrieve array of prices, that should be rendered for specific product\n         *\n         * @param {Array} row\n         * @return {Array}\n         */\n        getPrices: function (row) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                result;\n\n            //we cant take type of product from row\n            this.initPrices(row);\n            result = _.filter(elems, function (elem) {\n                return elem.productType === row.type;\n            });\n\n            return result;\n        },\n\n        /**\n         * Recursive Merging of objects\n         *\n         * @param {Array} target\n         * @param {Array} source\n         * @returns {Array}\n         * @private\n         */\n        _deepObjectExtend: function (target, source) {\n            var _target = utils.copy(target);\n\n            _.each(source, function (value, key) {\n                if (_.keys(value).length && typeof _target[key] !== 'undefined') {\n                    _target[key] = this._deepObjectExtend(_target[key], value);\n                } else {\n                    _target[key] = value;\n                }\n            }, this);\n\n            return _target;\n        },\n\n        /**\n         * Init price type box, in cases when product type has custom component or bodyTmpl\n         *\n         * @param {String} productType\n         * @private\n         */\n        _initPriceWithCustomMetaData: function (productType) {\n            var price = this._deepObjectExtend(\n                this.renders.prices['default'],\n                this.renders.prices[productType]\n            );\n\n            price.name = productType + '.default';\n            price.parent = this.name;\n            price.source = this.source;\n            price.productType = productType;\n            layout([price]);\n        },\n\n        /**\n         * Init Prices by product type and add them to layout\n         *\n         * @param {Array} _priceData\n         * @param {String} productType\n         * @private\n         */\n        _initPricesForProductType: function (_priceData, productType) {\n            var prices = [];\n\n            this._setPriceNamesToPrices(_priceData, productType);\n            _.sortBy(_priceData, this._comparePrices);\n\n            _.each(_priceData, function (priceData) {\n                if (!priceData.component) {\n                    return;\n                }\n\n                priceData.parent = this.name;\n                priceData.provider = this.provider;\n                priceData.productType = productType;\n                priceData = utils.template(priceData, this);\n                prices.push(priceData);\n            }, this);\n\n            layout(prices);\n        },\n\n        /**\n         * Init dynamic price components\n         *\n         * @param {Array} row\n         * @returns {void}\n         */\n        initPrices: function (row) {\n            var _priceData = [],\n                productType = row.type,\n                defaultPrice = this.renders.prices['default'];\n\n            if (this.pricesInit[productType]) {\n                return true;\n            }\n\n            this.pricesInit[productType] = true;\n\n            if (this.renders.prices[productType] && this._needToApplyCustomTemplate(this.renders.prices[productType])) {\n                return this._initPriceWithCustomMetaData(productType);\n            }\n\n            if (this.renders.prices[productType] && this.renders.prices[productType].children) {\n                _priceData = this._deepObjectExtend(defaultPrice.children, this.renders.prices[productType].children);\n            } else {\n                _priceData = defaultPrice.children;\n            }\n\n            return this._initPricesForProductType(_priceData, productType);\n        },\n\n        /**\n         * Set name to all price components\n         *\n         * @param {Array} prices\n         * @param {String} productType\n         * @private\n         */\n        _setPriceNamesToPrices: function (prices, productType) {\n            _.each(prices, function (price, name) {\n                price.priceType = name;\n                price.name = name + '.' + productType;\n            });\n\n            return prices;\n        },\n\n        /**\n         * Sort callback to compare prices by sort order\n         *\n         * @param {Number} firstPrice\n         * @param {Number} secondPrice\n         * @returns {Number}\n         * @private\n         */\n        _comparePrices: function (firstPrice, secondPrice) {\n            if (firstPrice.sortOrder < secondPrice.sortOrder) {\n                return -1;\n            }\n\n            if (firstPrice.sortOrder > secondPrice.sortOrder) {\n                return 1;\n            }\n\n            return 0;\n        },\n\n        /**\n         * Check whether metadata of product type prices was changed, and we should\n         * to apply custom template or custom component\n         *\n         * @param {Array} productData\n         * @returns {*}\n         * @private\n         */\n        _needToApplyCustomTemplate: function (productData) {\n            return productData.bodyTmpl || productData.component;\n        },\n\n        /**\n         * Returns path to the columns' body template.\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Get price label.\n         *\n         * @returns {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/final-price.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiCollection'\n], function (_, registry, utils, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            label: false,\n            headerTmpl: 'ui/grid/columns/text',\n            showMinimalPrice: false,\n            showMaximumPrice: false,\n            useLinkForAsLowAs: false,\n            bodyTmpl: 'Magento_Catalog/product/final_price',\n            priceWrapperCssClasses: '',\n            priceWrapperAttr: {}\n        },\n\n        /**\n         * Get product final price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} final price html\n         */\n        getPrice: function (row) {\n            return row['price_info']['formatted_prices']['final_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} final price html\n         */\n        getPriceUnsanitizedHtml: function (row) {\n            return this.getPrice(row);\n        },\n\n        /**\n         * Get product regular price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} regular price html\n         */\n        getRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} regular price html\n         */\n        getRegularPriceUnsanitizedHtml: function (row) {\n            return this.getRegularPrice(row);\n        },\n\n        /**\n         * Check if product has a price range.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        hasPriceRange: function (row) {\n            return row['price_info']['max_regular_price'] !== row['price_info']['min_regular_price'];\n        },\n\n        /**\n         * Check if product has special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} special price html\n         */\n        hasSpecialPrice: function (row) {\n            return row['price_info']['regular_price'] > row['price_info']['final_price'];\n        },\n\n        /**\n         * Check if product has minimal price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        isMinimalPrice: function (row) {\n            return row['price_info']['minimal_price'] < row['price_info']['final_price'];\n        },\n\n        /**\n         * Get product minimal price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        getMinimalPrice: function (row) {\n            return row['price_info']['formatted_prices']['minimal_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinimalPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        getMinimalPriceUnsanitizedHtml: function (row) {\n            return this.getMinimalPrice(row);\n        },\n\n        /**\n         * Check if product is salable.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        isSalable: function (row) {\n            return row['is_salable'];\n        },\n\n        /**\n         * Get product maximum price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum price html\n         */\n        getMaxPrice: function (row) {\n            return row['price_info']['formatted_prices']['max_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMaxPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum price html\n         */\n        getMaxPriceUnsanitizedHtml: function (row) {\n            return this.getMaxPrice(row);\n        },\n\n        /**\n         * Get product maximum regular price in case of price range and special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum regular price html\n         */\n        getMaxRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['max_regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMaxRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum regular price html\n         */\n        getMaxRegularPriceUnsanitizedHtml: function (row) {\n            return this.getMaxRegularPrice(row);\n        },\n\n        /**\n         * Get product minimal regular price in case of price range and special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal regular price html\n         */\n        getMinRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['min_regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal regular price html\n         */\n        getMinRegularPriceUnsanitizedHtml: function (row) {\n            return this.getMinRegularPrice(row);\n        },\n\n        /**\n         * Get adjustments names and return as string.\n         *\n         * @return {String} adjustments classes\n         */\n        getAdjustmentCssClasses: function () {\n            return _.pluck(this.getAdjustments(), 'index').join(' ');\n        },\n\n        /**\n         * Get product minimal price as number.\n         *\n         * @param {Object} row\n         * @return {Number} minimal price amount\n         */\n        getMinimalPriceAmount: function (row) {\n            return row['price_info']['minimal_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinimalPriceAmount\n         *\n         * @param {Object} row\n         * @return {Number} minimal price amount\n         */\n        getMinimalPriceAmountUnsanitizedHtml: function (row) {\n            return this.getMinimalPriceAmount(row);\n        },\n\n        /**\n         * Get product minimal regular price as number in case of special price.\n         *\n         * @param {Object} row\n         * @return {Number} minimal regular price amount\n         */\n        getMinimalRegularPriceAmount: function (row) {\n            return row['price_info']['min_regular_price'];\n        },\n\n        /**\n         * Get product maximum price as number.\n         *\n         * @param {Object} row\n         * @return {Number} maximum price amount\n         */\n        getMaximumPriceAmount: function (row) {\n            return row['price_info']['max_price'];\n        },\n\n        /**\n         * Get product maximum regular price as number in case of special price.\n         *\n         * @param {Object} row\n         * @return {Number} maximum regular price amount\n         */\n        getMaximumRegularPriceAmount: function (row) {\n            return row['price_info']['max_regular_price'];\n        },\n\n        /**\n         * Check if minimal regular price exist for product.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        showMinRegularPrice: function (row) {\n            return this.getMinimalPriceAmount(row) < this.getMinimalRegularPriceAmount(row);\n        },\n\n        /**\n         * Check if maximum regular price exist for product.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        showMaxRegularPrice: function (row) {\n            return this.getMaximumPriceAmount(row) < this.getMaximumRegularPriceAmount(row);\n        },\n\n        /**\n         * Get path to the columns' body template.\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Get all price adjustments.\n         *\n         * @returns {Object}\n         */\n        getAdjustments: function () {\n            var adjustments = this.elems();\n\n            _.each(adjustments, function (adjustment) {\n                adjustment.setPriceType(this.priceType);\n                adjustment.source = this.source;\n            }, this);\n\n            return adjustments;\n        }\n    });\n});\n","Magento_Catalog/js/product/view/product-ids-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Catalog/js/product/view/product-ids'\n], function (_, productIds) {\n    'use strict';\n\n    /**\n     * Returns id's of products in form.\n     *\n     * @param {jQuery} $form\n     * @return {Array}\n     */\n    return function ($form) {\n        var idSet = productIds(),\n            product = _.findWhere($form.serializeArray(), {\n            name: 'product'\n        });\n\n        if (!_.isUndefined(product)) {\n            idSet.push(product.value);\n        }\n\n        return _.uniq(idSet);\n    };\n});\n","Magento_Catalog/js/product/view/product-ids.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko'\n], function (ko) {\n    'use strict';\n\n    return ko.observableArray([]);\n});\n","Magento_Catalog/js/product/view/product-info-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Catalog/js/product/view/product-info'\n], function (_, productInfo) {\n    'use strict';\n\n    /**\n     * Returns info about products in form.\n     *\n     * @param {jQuery} $form\n     * @return {Array}\n     */\n    return function ($form) {\n        var product = _.findWhere($form.serializeArray(), {\n                name: 'product'\n            });\n\n        if (!_.isUndefined(product)) {\n            productInfo().push(\n                {\n                    'id': product.value\n                }\n            );\n        }\n\n        return _.uniq(productInfo(), function (item) {\n            return item.id;\n        });\n    };\n});\n\n","Magento_Catalog/js/product/view/provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiElement',\n    'Magento_Catalog/js/product/storage/storage-service'\n], function (_, Element, storage) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            identifiersConfig: {\n                namespace: 'recently_viewed_product'\n            },\n            productStorageConfig: {\n                namespace: 'product_data_storage',\n                updateRequestConfig: {\n                    method: 'GET',\n                    dataType: 'json'\n                },\n                className: 'DataStorage'\n            }\n        },\n\n        /**\n         * Initializes\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            this._super();\n\n            if (window.checkout && window.checkout.baseUrl) {\n                this.initIdsStorage();\n            }\n\n            this.initDataStorage();\n\n            return this;\n        },\n\n        /**\n         * Init ids storage\n         *\n         * @returns {Object} Chainable.\n         */\n        initIdsStorage: function () {\n            storage.onStorageInit(this.identifiersConfig.namespace, this.idsStorageHandler.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Init data storage\n         *\n         * @returns {Object} Chainable.\n         */\n        initDataStorage: function () {\n            storage.onStorageInit(this.productStorageConfig.namespace, this.dataStorageHandler.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Init data storage handler\n         *\n         * @param {Object} dataStorage - storage instance\n         */\n        dataStorageHandler: function (dataStorage) {\n            this.productStorage = dataStorage;\n            this.productStorage.add(this.data.items);\n        },\n\n        /**\n         * Init ids storage handler\n         *\n         * @param {Object} idsStorage - storage instance\n         */\n        idsStorageHandler: function (idsStorage) {\n            this.idsStorage = idsStorage;\n            this.idsStorage.add(this.getIdentifiers());\n        },\n\n        /**\n         * Gets ids from items\n         *\n         * @returns {Object}\n         */\n        getIdentifiers: function () {\n            var result = {},\n                productCurrentScope = this.data.productCurrentScope,\n                scopeId = productCurrentScope === 'store' ? window.checkout.storeId :\n                    productCurrentScope === 'group' ? window.checkout.storeGroupId :\n                        window.checkout.websiteId;\n\n            _.each(this.data.items, function (item, key) {\n                result[productCurrentScope + '-' + scopeId + '-' + key] = {\n                    'added_at': new Date().getTime() / 1000,\n                    'product_id': key,\n                    'scope_id': scopeId\n                };\n            }, this);\n\n            return result;\n        }\n    });\n});\n","Magento_Catalog/js/product/view/product-info.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko'\n], function (ko) {\n    'use strict';\n\n    return ko.observableArray([]);\n});\n","Magento_Catalog/js/product/storage/data-storage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'ko',\n    'mageUtils',\n    'Magento_Catalog/js/product/query-builder',\n    'Magento_Customer/js/customer-data',\n    'jquery/jquery-storageapi'\n], function ($, _, ko, utils, queryBuilder, customerData) {\n    'use strict';\n\n    /**\n     * Process data from API request\n     *\n     * @param {Object} data\n     * @returns {Object}\n     */\n    function getParsedDataFromServer(data) {\n        var result = {};\n\n        _.each(data.items, function (item) {\n                if (item.id) {\n                    result[item.id] = item;\n                }\n            }\n        );\n\n        return {\n            items: result\n        };\n    }\n\n    /**\n     * Set data to localStorage with support check.\n     *\n     * @param {String} namespace\n     * @param {Object} data\n     */\n    function setLocalStorageItem(namespace, data) {\n        try {\n            window.localStorage.setItem(namespace, JSON.stringify(data));\n        } catch (e) {\n            console.warn('localStorage is unavailable - skipping local caching of product data');\n            console.error(e);\n        }\n    }\n\n    return {\n\n        /**\n         * Class name\n         */\n        name: 'DataStorage',\n        request: {},\n        customerDataProvider: 'product_data_storage',\n\n        /**\n         * Initialize class\n         *\n         * @return Chainable.\n         */\n        initialize: function () {\n            if (!this.data) {\n                this.data = ko.observable({});\n            }\n\n            this.initLocalStorage()\n                .initCustomerDataReloadListener()\n                .cachesDataFromLocalStorage()\n                .initDataListener()\n                .initProvideStorage()\n                .initProviderListener();\n\n            return this;\n        },\n\n        /**\n         * Initialize listener to customer data reload\n         *\n         * @return Chainable.\n         */\n        initCustomerDataReloadListener: function () {\n            $(document).on('customer-data-invalidate', this._flushProductStorage.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Flush product storage\n         *\n         * @private\n         * @return void\n         */\n        _flushProductStorage: function (event, sections) {\n            if (_.isEmpty(sections) || _.contains(sections, 'product_data_storage')) {\n                this.localStorage.removeAll();\n            }\n        },\n\n        /**\n         * Initialize listener to data property\n         *\n         * @return Chainable.\n         */\n        initDataListener: function () {\n            this.data.subscribe(this.dataHandler.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Initialize provider storage\n         *\n         * @return Chainable.\n         */\n        initProvideStorage: function () {\n            this.providerHandler(customerData.get(this.customerDataProvider)());\n\n            return this;\n        },\n\n        /**\n         * Handler to update \"data\" property.\n         * Sets data to localStorage\n         *\n         * @param {Object} data\n         */\n        dataHandler: function (data) {\n            if (_.isEmpty(data)) {\n                this.localStorage.removeAll();\n            } else {\n                setLocalStorageItem(this.namespace, data);\n            }\n        },\n\n        /**\n         * Handler to update data in provider.\n         *\n         * @param {Object} data\n         */\n        providerHandler: function (data) {\n            var currentData = utils.copy(this.data()),\n                ids = _.keys(data.items);\n\n            if (data.items && ids.length) {\n                //we can extend only items\n                data = data.items;\n                this.data(_.extend(data, currentData));\n            }\n        },\n\n        /**\n         * Sets data ids\n         *\n         * @param {String} currency\n         * @param {String} store\n         * @param {Object} ids\n         */\n        setIds: function (currency, store, ids) {\n            if (!this.hasInCache(currency, store, ids)) {\n                this.loadDataFromServer(currency, store, ids);\n            } else {\n                this.data.valueHasMutated();\n            }\n        },\n\n        /**\n         * Gets data from \"data\" property by identifiers\n         *\n         * @param {String} currency\n         * @param {String} store\n         * @param {Object} productIdentifiers\n         *\n         * @return {Object} data.\n         */\n        getDataByIdentifiers: function (currency, store, productIdentifiers) {\n            var data = {},\n                dataCollection = this.data(),\n                id;\n\n            for (id in productIdentifiers) {\n                if (productIdentifiers.hasOwnProperty(id)) {\n                    data[id] = dataCollection[id];\n                }\n            }\n\n            return data;\n        },\n\n        /**\n         * Checks has cached data or not\n         *\n         * @param {String} currency\n         * @param {String} store\n         * @param {Object} ids\n         *\n         * @return {Boolean}\n         */\n        hasInCache: function (currency, store, ids) {\n            var data = this.data(),\n                id;\n\n            for (id in ids) {\n                if (!data.hasOwnProperty(id) ||\n                    data[id]['currency_code'] !== currency ||\n                    ~~data[id]['store_id'] !== ~~store\n                ) {\n                    return false;\n                }\n            }\n\n            return true;\n        },\n\n        /**\n         * Load data from server by ids\n         *\n         * @param {String} currency\n         * @param {String} store\n         * @param {Object} ids\n         *\n         * @return void\n         */\n        loadDataFromServer: function (currency, store, ids) {\n            var idsArray = _.keys(ids),\n                prepareAjaxParams = {\n                    'entity_id': idsArray.join(',')\n                };\n\n            if (this.request.sent && this.hasIdsInSentRequest(ids)) {\n                return;\n            }\n\n            this.request = {\n                sent: true,\n                data: ids\n            };\n\n            this.updateRequestConfig.data = queryBuilder.buildQuery(prepareAjaxParams);\n            this.updateRequestConfig.data['store_id'] = store;\n            this.updateRequestConfig.data['currency_code'] = currency;\n            $.ajax(this.updateRequestConfig).done(function (data) {\n                this.request = {};\n                this.providerHandler(getParsedDataFromServer(data));\n            }.bind(this));\n        },\n\n        /**\n         * Each product page consist product cache data,\n         * this function prepare those data to appropriate view, and save it\n         *\n         * @param {Object} data\n         */\n        addDataFromPageCache: function (data) {\n            this.providerHandler(getParsedDataFromServer(data));\n        },\n\n        /**\n         * @param {Object} ids\n         * @returns {Boolean}\n         */\n        hasIdsInSentRequest: function (ids) {\n            var sentDataIds,\n                currentDataIds;\n\n            if (this.request.data) {\n                sentDataIds = _.keys(this.request.data);\n                currentDataIds = _.keys(ids);\n\n                _.each(currentDataIds, function (id) {\n                    if (_.lastIndexOf(sentDataIds, id) === -1) {\n                        return false;\n                    }\n                });\n\n                return true;\n            }\n\n            return false;\n        },\n\n        /**\n         * Initialize provider listener\n         *\n         * @return Chainable.\n         */\n        initProviderListener: function () {\n            customerData.get(this.customerDataProvider).subscribe(this.providerHandler.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Caches data from local storage to local scope\n         *\n         * @return Chainable.\n         */\n        cachesDataFromLocalStorage: function () {\n            this.data(this.getDataFromLocalStorage());\n\n            return this;\n        },\n\n        /**\n         * Gets data from local storage by current namespace\n         *\n         * @return {Object}.\n         */\n        getDataFromLocalStorage: function () {\n            return this.localStorage.get();\n        },\n\n        /**\n         * Initialize localStorage\n         *\n         * @return Chainable.\n         */\n        initLocalStorage: function () {\n            this.localStorage = $.initNamespaceStorage(this.namespace).localStorage;\n\n            return this;\n        }\n    };\n});\n","Magento_Catalog/js/product/storage/storage-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'mage/translate',\n    'Magento_Catalog/js/product/storage/ids-storage',\n    'Magento_Catalog/js/product/storage/data-storage',\n    'Magento_Catalog/js/product/storage/ids-storage-compare'\n], function ($, _, utils, $t, IdsStorage, DataStore, IdsStorageCompare) {\n    'use strict';\n\n    return (function () {\n\n        var /**\n             * {Object} storages - list of storages\n             */\n            storages = {},\n\n            /**\n             * {Object} classes - list of classes\n             */\n            classes = {},\n\n            /**\n             * {Object} prototype - methods that will be added to all storage classes to prototype property.\n             */\n            prototype = {\n\n                /**\n                 * Sets data to storage\n                 *\n                 * @param {*} data\n                 */\n                set: function (data) {\n                    if (!utils.compare(data, this.data()).equal) {\n                        this.data(data);\n                    }\n                },\n\n                /**\n                 * Adds some data to current storage data\n                 *\n                 * @param {*} data\n                 */\n                add: function (data) {\n                    if (!_.isEmpty(data)) {\n                        this.data(_.extend(utils.copy(this.data()), data));\n                    }\n                },\n\n                /**\n                 * Gets current storage data\n                 *\n                 * @returns {*} data\n                 */\n                get: function () {\n                    return this.data();\n                }\n            },\n\n            /**\n             * Required properties to storage\n             */\n            storagesInterface =  {\n                data: 'function',\n                initialize: 'function',\n                namespace: 'string'\n            },\n\n            /**\n             * Private service methods\n             */\n            _private = {\n\n                /**\n                 * Overrides class method and add ability use _super to call parent method\n                 *\n                 * @param {Object} extensionMethods\n                 * @param {Object} originInstance\n                 */\n                overrideClassMethods: function (extensionMethods, originInstance) {\n                    var methodsName = _.keys(extensionMethods),\n                        i = 0,\n                        length = methodsName.length;\n\n                    for (i; i < length; i++) {\n                        if (_.isFunction(originInstance[methodsName[i]])) {\n                            originInstance[methodsName[i]] = extensionMethods[methodsName[i]];\n                        }\n                    }\n\n                    return originInstance;\n                },\n\n                /**\n                 * Checks is storage implement interface\n                 *\n                 * @param {Object} classInstance\n                 *\n                 * @returns {Boolean}\n                 */\n                isImplementInterface: function (classInstance) {\n                    _.each(storagesInterface, function (key, value) {\n                        if (typeof classInstance[key] !== value) {\n                            return false;\n                        }\n                    });\n\n                    return true;\n                }\n            },\n\n            /**\n             * Subscribers list\n             */\n            subsctibers = {};\n\n        (function () {\n            /**\n             * @param {Object} config\n             * @return void\n             */\n            classes[IdsStorage.name] = function (config) {\n                _.extend(this, IdsStorage, config);\n            };\n\n            /**\n             * @param {Object} config\n             * @return void\n             */\n            classes[IdsStorageCompare.name] = function (config) {\n                _.extend(this, IdsStorageCompare, config);\n            };\n\n            /**\n             * @param {Object} config\n             * @return void\n             */\n            classes[DataStore.name] = function (config) {\n                _.extend(this, DataStore, config);\n            };\n\n            _.each(classes, function (classItem) {\n                classItem.prototype = prototype;\n            });\n        })();\n\n        return {\n\n            /**\n             * Creates new storage or returns if storage with declared namespace exist\n             *\n             * @param {Object} config - storage config\n             * @throws {Error}\n             * @returns {Object} storage instance\n             */\n            createStorage: function (config) {\n                var instance,\n                    initialized;\n\n                if (storages[config.namespace]) {\n                    return storages[config.namespace];\n                }\n\n                instance = new classes[config.className](config);\n\n                if (_private.isImplementInterface(instance)) {\n                    initialized = storages[config.namespace] = instance.initialize();\n                    this.processSubscribers(initialized, config);\n\n                    return initialized;\n                }\n\n                throw new Error('Class ' + config.className + $t('does not implement Storage Interface'));\n            },\n\n            /**\n             * Process subscribers\n             *\n             * Differentiate subscribers by their namespaces: recently_viewed or recently_compared\n             * and process callbacks. Callbacks can be add through onStorageInit function\n             *\n             * @param {Object} initialized\n             * @param {Object} config\n             * @return void\n             */\n            processSubscribers: function (initialized, config) {\n                if (subsctibers[config.namespace]) {\n                    _.each(subsctibers[config.namespace], function (callback) {\n                        callback(initialized);\n                    });\n\n                    delete subsctibers[config.namespace];\n                }\n            },\n\n            /**\n             * Listens storage creating by namespace\n             *\n             * @param {String} namespace\n             * @param {Function} callback\n             * @return void\n             */\n            onStorageInit: function (namespace, callback) {\n                if (storages[namespace]) {\n                    callback(storages[namespace]);\n                } else {\n                    subsctibers[namespace] ?\n                        subsctibers[namespace].push(callback) :\n                        subsctibers[namespace] = [callback];\n                }\n            },\n\n            /**\n             * Gets storage by namespace\n             *\n             * @param {String} namespace\n             *\n             * @returns {Object} storage insance\n             */\n            getStorage: function (namespace) {\n                return storages[namespace];\n            }\n        };\n    })();\n});\n\n","Magento_Catalog/js/product/storage/ids-storage-compare.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'ko',\n    'mageUtils',\n    'Magento_Customer/js/customer-data',\n    'Magento_Catalog/js/product/storage/ids-storage'\n], function (_, ko, utils, customerData, idsStorage) {\n    'use strict';\n\n    return _.extend(utils.copy(idsStorage), {\n\n        /**\n         * Class name\n         */\n        name: 'IdsStorageCompare',\n\n        /**\n         * Initializes class\n         *\n         * @return Chainable.\n         */\n        initialize: function () {\n            if (!this.data) {\n                this.data = ko.observable({});\n            }\n\n            if (this.provider && window.checkout && window.checkout.baseUrl) {\n                this.providerDataHandler(customerData.get(this.provider)());\n                this.initProviderListener();\n            }\n\n            this.initLocalStorage()\n                .cachesDataFromLocalStorage()\n                .initDataListener();\n\n            return this;\n        },\n\n        /**\n         * Initializes listener for external data provider\n         */\n        initProviderListener: function () {\n            customerData.get(this.provider).subscribe(this.providerDataHandler.bind(this));\n        },\n\n        /**\n         * Initializes handler for external data provider update\n         *\n         * @param {Object} data\n         */\n        providerDataHandler: function (data) {\n            data = data.items || data;\n            data = this.prepareData(data);\n\n            this.add(data);\n        },\n\n        /**\n         * Prepares data to correct interface\n         *\n         * @param {Object} data\n         *\n         * @returns {Object} data\n         */\n        prepareData: function (data) {\n            var result = {},\n                scopeId;\n\n            _.each(data, function (item) {\n                if (typeof item.productScope !== 'undefined') {\n                    scopeId = item.productScope === 'store' ? window.checkout.storeId :\n                        item.productScope === 'group' ? window.checkout.storeGroupId :\n                            window.checkout.websiteId;\n\n                    result[item.productScope + '-' + scopeId + '-' + item.id] = {\n                        'added_at': new Date().getTime() / 1000,\n                        'product_id': item.id,\n                        'scope_id': scopeId\n                    };\n                } else {\n                    result[item.id] = {\n                        'added_at': new Date().getTime() / 1000,\n                        'product_id': item.id\n                    };\n                }\n            });\n\n            return result;\n        }\n    });\n});\n","Magento_Catalog/js/product/storage/ids-storage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'ko',\n    'mageUtils',\n    'jquery/jquery-storageapi'\n], function ($, _, ko, utils) {\n    'use strict';\n\n    /**\n     * Set data to localStorage with support check.\n     *\n     * @param {String} namespace\n     * @param {Object} data\n     */\n    function setLocalStorageItem(namespace, data) {\n        try {\n            window.localStorage.setItem(namespace, JSON.stringify(data));\n        } catch (e) {\n            console.warn('localStorage is unavailable - skipping local caching of product data');\n            console.error(e);\n        }\n    }\n\n    return {\n\n        /**\n         * Class name\n         */\n        name: 'IdsStorage',\n\n        /**\n         * Initializes class\n         *\n         * @return Chainable.\n         */\n        initialize: function () {\n            if (!this.data) {\n                this.data = ko.observable({});\n            }\n\n            this.initCustomerDataReloadListener()\n                .initLocalStorage()\n                .cachesDataFromLocalStorage()\n                .initDataListener();\n\n            return this;\n        },\n\n        /**\n         * Gets data from local storage by current namespace\n         *\n         * @return {Object}.\n         */\n        getDataFromLocalStorage: function () {\n            return this.localStorage.get();\n        },\n\n        /**\n         * Caches data from local storage to local scope\n         *\n         * @return Chainable.\n         */\n        cachesDataFromLocalStorage: function () {\n            this.data(this.getDataFromLocalStorage());\n\n            return this;\n        },\n\n        /**\n         * Initialize localStorage\n         *\n         * @return Chainable.\n         */\n        initLocalStorage: function () {\n            this.localStorage = $.initNamespaceStorage(this.namespace).localStorage;\n\n            return this;\n        },\n\n        /**\n         * Initializes listener to \"data\" property\n         */\n        initDataListener: function () {\n            this.data.subscribe(this.internalDataHandler.bind(this));\n        },\n\n        /**\n         * Initialize listener to customer data reload\n         *\n         * @return Chainable.\n         */\n        initCustomerDataReloadListener: function () {\n            $(document).on('customer-data-reload', function (event, sections) {\n                if ((_.isEmpty(sections) || _.contains(sections, this.namespace)) && ~~this.allowToSendRequest) {\n                    this.localStorage.removeAll();\n                    this.data();\n                }\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Initializes handler to \"data\" property update\n         */\n        internalDataHandler: function (data) {\n            setLocalStorageItem(this.namespace, data);\n        },\n\n        /**\n         * Initializes handler to storage update\n         */\n        externalDataHandler: function (data) {\n            data = data.items ? data.items : data;\n\n            this.set(_.extend(utils.copy(this.data()), data));\n        }\n    };\n});\n\n","Magento_Catalog/js/view/image.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n\n            this.template = window.checkout.imageTemplate || this.template;\n        }\n    });\n});\n","Magento_Catalog/js/view/compare-products.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Customer/js/customer-data',\n    'jquery',\n    'underscore',\n    'mage/mage',\n    'mage/decorate'\n], function (Component, customerData, $, _) {\n    'use strict';\n\n    var sidebarInitialized = false,\n        compareProductsReloaded = false;\n\n    /**\n     * Initialize sidebar\n     */\n    function initSidebar() {\n        if (sidebarInitialized) {\n            return;\n        }\n\n        sidebarInitialized = true;\n        $('[data-role=compare-products-sidebar]').decorate('list', true);\n    }\n\n    return Component.extend({\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.compareProducts = customerData.get('compare-products');\n            if (!compareProductsReloaded\n                && !_.isEmpty(this.compareProducts())\n                //Expired section names are reloaded on page load\n                && _.indexOf(customerData.getExpiredSectionNames(), 'compare-products') === -1\n                && window.checkout\n                && window.checkout.websiteId\n                && window.checkout.websiteId !== this.compareProducts().websiteId\n            ) {\n                //set count to 0 to prevent \"compared products\" blocks and count to show with wrong count and items\n                this.compareProducts().count = 0;\n                customerData.reload(['compare-products'], false);\n                compareProductsReloaded = true;\n            }\n            initSidebar();\n        }\n    });\n});\n","Magento_Catalog/product/view/validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget',\n    'mage/validation/validation'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.validation', $.mage.validation, {\n        options: {\n            radioCheckboxClosest: 'ul, ol',\n\n            /**\n             * @param {*} error\n             * @param {HTMLElement} element\n             */\n            errorPlacement: function (error, element) {\n                var messageBox,\n                    dataValidate;\n\n                if ($(element).hasClass('datetime-picker')) {\n                    element = $(element).parent();\n\n                    if (element.parent().find('.mage-error').length) {\n                        return;\n                    }\n                }\n\n                if (element.attr('data-errors-message-box')) {\n                    messageBox = $(element.attr('data-errors-message-box'));\n                    messageBox.html(error);\n\n                    return;\n                }\n\n                dataValidate = element.attr('data-validate');\n\n                if (dataValidate && dataValidate.indexOf('validate-one-checkbox-required-by-name') > 0) {\n                    error.appendTo('#links-advice-container');\n                } else if (element.is(':radio, :checkbox')) {\n                    element.closest(this.radioCheckboxClosest).after(error);\n                } else {\n                    element.after(error);\n                }\n            },\n\n            /**\n             * @param {HTMLElement} element\n             * @param {String} errorClass\n             */\n            highlight: function (element, errorClass) {\n                var dataValidate = $(element).attr('data-validate');\n\n                if (dataValidate && dataValidate.indexOf('validate-required-datetime') > 0) {\n                    $(element).parent().find('.datetime-picker').each(function () {\n                        $(this).removeClass(errorClass);\n\n                        if ($(this).val().length === 0) {\n                            $(this).addClass(errorClass);\n                        }\n                    });\n                } else if ($(element).is(':radio, :checkbox')) {\n                    $(element).closest(this.radioCheckboxClosest).addClass(errorClass);\n                } else {\n                    $(element).addClass(errorClass);\n                }\n            },\n\n            /**\n             * @param {HTMLElement} element\n             * @param {String} errorClass\n             */\n            unhighlight: function (element, errorClass) {\n                var dataValidate = $(element).attr('data-validate');\n\n                if (dataValidate && dataValidate.indexOf('validate-required-datetime') > 0) {\n                    $(element).parent().find('.datetime-picker').removeClass(errorClass);\n                } else if ($(element).is(':radio, :checkbox')) {\n                    $(element).closest(this.radioCheckboxClosest).removeClass(errorClass);\n                } else {\n                    $(element).removeClass(errorClass);\n                }\n            }\n        }\n    });\n\n    return $.mage.validation;\n});\n","Magento_Checkout/js/discount-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.discountCode', {\n        options: {\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this.couponCode = $(this.options.couponCodeSelector);\n            this.removeCoupon = $(this.options.removeCouponSelector);\n\n            $(this.options.applyButton).on('click', $.proxy(function () {\n                this.couponCode.attr('data-validate', '{required:true}');\n                this.removeCoupon.attr('value', '0');\n                $(this.element).validation().trigger('submit');\n            }, this));\n\n            $(this.options.cancelButton).on('click', $.proxy(function () {\n                this.couponCode.removeAttr('data-validate');\n                this.removeCoupon.attr('value', '1');\n                this.element.trigger('submit');\n            }, this));\n        }\n    });\n\n    return $.mage.discountCode;\n});\n","Magento_Checkout/js/region-updater.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/template',\n    'underscore',\n    'jquery-ui-modules/widget',\n    'mage/validation'\n], function ($, mageTemplate, _) {\n    'use strict';\n\n    $.widget('mage.regionUpdater', {\n        options: {\n            regionTemplate:\n                '<option value=\"<%- data.value %>\" <% if (data.isSelected) { %>selected=\"selected\"<% } %>>' +\n                    '<%- data.title %>' +\n                '</option>',\n            isRegionRequired: true,\n            isZipRequired: true,\n            isCountryRequired: true,\n            currentRegion: null,\n            isMultipleCountriesAllowed: true\n        },\n\n        /**\n         *\n         * @private\n         */\n        _create: function () {\n            this._initCountryElement();\n\n            this.currentRegionOption = this.options.currentRegion;\n            this.regionTmpl = mageTemplate(this.options.regionTemplate);\n\n            this._updateRegion(this.element.find('option:selected').val());\n\n            $(this.options.regionListId).on('change', $.proxy(function (e) {\n                this.setOption = false;\n                this.currentRegionOption = $(e.target).val();\n            }, this));\n\n            $(this.options.regionInputId).on('focusout', $.proxy(function () {\n                this.setOption = true;\n            }, this));\n        },\n\n        /**\n         *\n         * @private\n         */\n        _initCountryElement: function () {\n\n            if (this.options.isMultipleCountriesAllowed) {\n                this.element.parents('div.field').show();\n                this.element.on('change', $.proxy(function (e) {\n                    // clear region inputs on country change\n                    $(this.options.regionListId).val('');\n                    $(this.options.regionInputId).val('');\n                    this._updateRegion($(e.target).val());\n                }, this));\n\n                if (this.options.isCountryRequired) {\n                    this.element.addClass('required-entry');\n                    this.element.parents('div.field').addClass('required');\n                }\n            } else {\n                this.element.parents('div.field').hide();\n            }\n        },\n\n        /**\n         * Remove options from dropdown list\n         *\n         * @param {Object} selectElement - jQuery object for dropdown list\n         * @private\n         */\n        _removeSelectOptions: function (selectElement) {\n            selectElement.find('option').each(function (index) {\n                if (index) {\n                    $(this).remove();\n                }\n            });\n        },\n\n        /**\n         * Render dropdown list\n         * @param {Object} selectElement - jQuery object for dropdown list\n         * @param {String} key - region code\n         * @param {Object} value - region object\n         * @private\n         */\n        _renderSelectOption: function (selectElement, key, value) {\n            selectElement.append($.proxy(function () {\n                var name = value.name.replace(/[!\"#$%&'()*+,.\\/:;<=>?@[\\\\\\]^`{|}~]/g, '\\\\$&'),\n                    tmplData,\n                    tmpl;\n\n                if (value.code && $(name).is('span')) {\n                    key = value.code;\n                    value.name = $(name).text();\n                }\n\n                tmplData = {\n                    value: key,\n                    title: value.name,\n                    isSelected: false\n                };\n\n                if (this.options.defaultRegion === key) {\n                    tmplData.isSelected = true;\n                }\n\n                tmpl = this.regionTmpl({\n                    data: tmplData\n                });\n\n                return $(tmpl);\n            }, this));\n        },\n\n        /**\n         * Takes clearError callback function as first option\n         * If no form is passed as option, look up the closest form and call clearError method.\n         * @private\n         */\n        _clearError: function () {\n            var args = ['clearError', this.options.regionListId, this.options.regionInputId, this.options.postcodeId];\n\n            if (this.options.clearError && typeof this.options.clearError === 'function') {\n                this.options.clearError.call(this);\n            } else {\n                if (!this.options.form) {\n                    this.options.form = this.element.closest('form').length ? $(this.element.closest('form')[0]) : null;\n                }\n\n                this.options.form = $(this.options.form);\n\n                this.options.form && this.options.form.data('validator') &&\n                    this.options.form.validation.apply(this.options.form, _.compact(args));\n\n                // Clean up errors on region & zip fix\n                $(this.options.regionInputId).removeClass('mage-error').parent().find('.mage-error').remove();\n                $(this.options.regionListId).removeClass('mage-error').parent().find('.mage-error').remove();\n                $(this.options.postcodeId).removeClass('mage-error').parent().find('.mage-error').remove();\n            }\n        },\n\n        /**\n         * Update dropdown list based on the country selected\n         *\n         * @param {String} country - 2 uppercase letter for country code\n         * @private\n         */\n        _updateRegion: function (country) {\n            // Clear validation error messages\n            var regionList = $(this.options.regionListId),\n                regionInput = $(this.options.regionInputId),\n                postcode = $(this.options.postcodeId),\n                label = regionList.parent().siblings('label'),\n                container = regionList.parents('div.field'),\n                regionsEntries,\n                regionId,\n                regionData;\n\n            this._clearError();\n            this._checkRegionRequired(country);\n\n            // Populate state/province dropdown list if available or use input box\n            if (this.options.regionJson[country]) {\n                this._removeSelectOptions(regionList);\n                regionsEntries = _.pairs(this.options.regionJson[country]);\n                regionsEntries.sort(function (a, b) {\n                    return a[1].name > b[1].name ? 1 : -1;\n                });\n                $.each(regionsEntries, $.proxy(function (key, value) {\n                    regionId = value[0];\n                    regionData = value[1];\n                    this._renderSelectOption(regionList, regionId, regionData);\n                }, this));\n\n                if (this.currentRegionOption) {\n                    regionList.val(this.currentRegionOption);\n                }\n\n                if (this.setOption) {\n                    regionList.find('option').filter(function () {\n                        return this.text === regionInput.val();\n                    }).attr('selected', true);\n                }\n\n                if (this.options.isRegionRequired) {\n                    regionList.addClass('required-entry').prop('disabled', false);\n                    container.addClass('required').show();\n                } else {\n                    regionList.removeClass('required-entry validate-select').removeAttr('data-validate');\n                    container.removeClass('required');\n\n                    if (!this.options.optionalRegionAllowed) { //eslint-disable-line max-depth\n                        regionList.hide();\n                        container.hide();\n                    } else {\n                        regionList.prop('disabled', false).show();\n                    }\n                }\n\n                regionList.show();\n                regionInput.hide();\n                label.attr('for', regionList.attr('id'));\n            } else {\n                this._removeSelectOptions(regionList);\n\n                if (this.options.isRegionRequired) {\n                    regionInput.addClass('required-entry').prop('disabled', false);\n                    container.addClass('required').show();\n                } else {\n                    if (!this.options.optionalRegionAllowed) { //eslint-disable-line max-depth\n                        regionInput.attr('disabled', 'disabled');\n                        container.hide();\n                    }\n                    container.removeClass('required');\n                    regionInput.removeClass('required-entry');\n                }\n\n                regionList.removeClass('required-entry').prop('disabled', 'disabled').hide();\n                regionInput.show();\n                label.attr('for', regionInput.attr('id'));\n            }\n\n            // If country is in optionalzip list, make postcode input not required\n            if (this.options.isZipRequired) {\n                $.inArray(country, this.options.countriesWithOptionalZip) >= 0 ?\n                    postcode.removeClass('required-entry').closest('.field').removeClass('required') :\n                    postcode.addClass('required-entry').closest('.field').addClass('required');\n            }\n\n            // Add defaultvalue attribute to state/province select element\n            regionList.attr('defaultvalue', this.options.defaultRegion);\n            this.options.form.find('[type=\"submit\"]').prop('disabled', false).show();\n        },\n\n        /**\n         * Check if the selected country has a mandatory region selection\n         *\n         * @param {String} country - Code of the country - 2 uppercase letter for country code\n         * @private\n         */\n        _checkRegionRequired: function (country) {\n            var self = this;\n\n            this.options.isRegionRequired = false;\n            $.each(this.options.regionJson.config['regions_required'], function (index, elem) {\n                if (elem === country) {\n                    self.options.isRegionRequired = true;\n                }\n            });\n        }\n    });\n\n    return $.mage.regionUpdater;\n});\n","Magento_Checkout/js/empty-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_Customer/js/customer-data'], function (customerData) {\n    'use strict';\n\n    return function () {\n        var cartData = customerData.get('cart');\n\n        customerData.getInitCustomerData().done(function () {\n            if (cartData().items && cartData().items.length !== 0) {\n                customerData.reload(['cart'], false);\n            }\n        });\n    };\n});\n","Magento_Checkout/js/sidebar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Customer/js/model/authentication-popup',\n    'Magento_Customer/js/customer-data',\n    'Magento_Ui/js/modal/alert',\n    'Magento_Ui/js/modal/confirm',\n    'underscore',\n    'jquery-ui-modules/widget',\n    'mage/decorate',\n    'mage/collapsible',\n    'mage/cookies',\n    'jquery-ui-modules/effect-fade'\n], function ($, authenticationPopup, customerData, alert, confirm, _) {\n    'use strict';\n\n    $.widget('mage.sidebar', {\n        options: {\n            isRecursive: true,\n            minicart: {\n                maxItemsVisible: 3\n            }\n        },\n        scrollHeight: 0,\n        shoppingCartUrl: window.checkout.shoppingCartUrl,\n\n        /**\n         * Create sidebar.\n         * @private\n         */\n        _create: function () {\n            this._initContent();\n        },\n\n        /**\n         * Update sidebar block.\n         */\n        update: function () {\n            $(this.options.targetElement).trigger('contentUpdated');\n            this._calcHeight();\n        },\n\n        /**\n         * @private\n         */\n        _initContent: function () {\n            var self = this,\n                events = {};\n\n            this.element.decorate('list', this.options.isRecursive);\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['click ' + this.options.button.close] = function (event) {\n                event.stopPropagation();\n                $(self.options.targetElement).dropdownDialog('close');\n            };\n            events['click ' + this.options.button.checkout] = $.proxy(function () {\n                var cart = customerData.get('cart'),\n                    customer = customerData.get('customer'),\n                    element = $(this.options.button.checkout);\n\n                if (!customer().firstname && cart().isGuestCheckoutAllowed === false) {\n                    // set URL for redirect on successful login/registration. It's postprocessed on backend.\n                    $.cookie('login_redirect', this.options.url.checkout);\n\n                    if (this.options.url.isRedirectRequired) {\n                        element.prop('disabled', true);\n                        location.href = this.options.url.loginUrl;\n                    } else {\n                        authenticationPopup.showModal();\n                    }\n\n                    return false;\n                }\n                element.prop('disabled', true);\n                location.href = this.options.url.checkout;\n            }, this);\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['click ' + this.options.button.remove] =  function (event) {\n                event.stopPropagation();\n                confirm({\n                    content: self.options.confirmMessage,\n                    actions: {\n                        /** @inheritdoc */\n                        confirm: function () {\n                            self._removeItem($(event.currentTarget));\n                        },\n\n                        /** @inheritdoc */\n                        always: function (e) {\n                            e.stopImmediatePropagation();\n                        }\n                    }\n                });\n            };\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['keyup ' + this.options.item.qty] = function (event) {\n                self._showItemButton($(event.target));\n            };\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['change ' + this.options.item.qty] = function (event) {\n                self._showItemButton($(event.target));\n            };\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['click ' + this.options.item.button] = function (event) {\n                event.stopPropagation();\n                self._updateItemQty($(event.currentTarget));\n            };\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['focusout ' + this.options.item.qty] = function (event) {\n                self._validateQty($(event.currentTarget));\n            };\n\n            this._on(this.element, events);\n            this._calcHeight();\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         */\n        _showItemButton: function (elem) {\n            var itemId = elem.data('cart-item'),\n                itemQty = elem.data('item-qty');\n\n            if (this._isValidQty(itemQty, elem.val())) {\n                $('#update-cart-item-' + itemId).show('fade', 300);\n            } else if (elem.val() == 0) { //eslint-disable-line eqeqeq\n                this._hideItemButton(elem);\n            } else {\n                this._hideItemButton(elem);\n            }\n        },\n\n        /**\n         * @param {*} origin - origin qty. 'data-item-qty' attribute.\n         * @param {*} changed - new qty.\n         * @returns {Boolean}\n         * @private\n         */\n        _isValidQty: function (origin, changed) {\n            return origin != changed && //eslint-disable-line eqeqeq\n                changed.length > 0 &&\n                changed - 0 == changed && //eslint-disable-line eqeqeq\n                changed - 0 > 0;\n        },\n\n        /**\n         * @param {Object} elem\n         * @private\n         */\n        _validateQty: function (elem) {\n            var itemQty = elem.data('item-qty');\n\n            if (!this._isValidQty(itemQty, elem.val())) {\n                elem.val(itemQty);\n            }\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         */\n        _hideItemButton: function (elem) {\n            var itemId = elem.data('cart-item');\n\n            $('#update-cart-item-' + itemId).hide('fade', 300);\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         */\n        _updateItemQty: function (elem) {\n            var itemId = elem.data('cart-item');\n\n            this._ajax(this.options.url.update, {\n                'item_id': itemId,\n                'item_qty': $('#cart-item-' + itemId + '-qty').val()\n            }, elem, this._updateItemQtyAfter);\n        },\n\n        /**\n         * Update content after update qty\n         *\n         * @param {HTMLElement} elem\n         */\n        _updateItemQtyAfter: function (elem) {\n            var productData = this._getProductById(Number(elem.data('cart-item')));\n\n            if (!_.isUndefined(productData)) {\n                $(document).trigger('ajax:updateCartItemQty');\n\n                if (window.location.href === this.shoppingCartUrl) {\n                    window.location.reload(false);\n                }\n            }\n            this._hideItemButton(elem);\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         */\n        _removeItem: function (elem) {\n            var itemId = elem.data('cart-item');\n\n            this._ajax(this.options.url.remove, {\n                'item_id': itemId\n            }, elem, this._removeItemAfter);\n        },\n\n        /**\n         * Update content after item remove\n         *\n         * @param {Object} elem\n         * @private\n         */\n        _removeItemAfter: function (elem) {\n            var productData = this._getProductById(Number(elem.data('cart-item')));\n\n            if (!_.isUndefined(productData)) {\n                $(document).trigger('ajax:removeFromCart', {\n                    productIds: [productData['product_id']],\n                    productInfo: [\n                        {\n                            'id': productData['product_id']\n                        }\n                    ]\n                });\n\n                if (window.location.href.indexOf(this.shoppingCartUrl) === 0) {\n                    window.location.reload();\n                }\n            }\n        },\n\n        /**\n         * Retrieves product data by Id.\n         *\n         * @param {Number} productId - product Id\n         * @returns {Object|undefined}\n         * @private\n         */\n        _getProductById: function (productId) {\n            return _.find(customerData.get('cart')().items, function (item) {\n                return productId === Number(item['item_id']);\n            });\n        },\n\n        /**\n         * @param {String} url - ajax url\n         * @param {Object} data - post data for ajax call\n         * @param {Object} elem - element that initiated the event\n         * @param {Function} callback - callback method to execute after AJAX success\n         */\n        _ajax: function (url, data, elem, callback) {\n            $.extend(data, {\n                'form_key': $.mage.cookies.get('form_key')\n            });\n\n            $.ajax({\n                url: url,\n                data: data,\n                type: 'post',\n                dataType: 'json',\n                context: this,\n\n                /** @inheritdoc */\n                beforeSend: function () {\n                    elem.attr('disabled', 'disabled');\n                },\n\n                /** @inheritdoc */\n                complete: function () {\n                    elem.attr('disabled', null);\n                }\n            })\n                .done(function (response) {\n                    var msg;\n\n                    if (response.success) {\n                        callback.call(this, elem, response);\n                    } else {\n                        msg = response['error_message'];\n\n                        if (msg) {\n                            alert({\n                                content: msg\n                            });\n                        }\n                    }\n                })\n                .fail(function (error) {\n                    console.log(JSON.stringify(error));\n                });\n        },\n\n        /**\n         * Calculate height of minicart list\n         *\n         * @private\n         */\n        _calcHeight: function () {\n            var self = this,\n                height = 0,\n                counter = this.options.minicart.maxItemsVisible,\n                target = $(this.options.minicart.list),\n                outerHeight;\n\n            self.scrollHeight = 0;\n            target.children().each(function () {\n\n                if ($(this).find('.options').length > 0) {\n                    $(this).collapsible();\n                }\n                outerHeight = $(this).outerHeight(true);\n\n                if (counter-- > 0) {\n                    height += outerHeight;\n                }\n                self.scrollHeight += outerHeight;\n            });\n\n            target.parent().height(height);\n        }\n    });\n\n    return $.mage.sidebar;\n});\n","Magento_Checkout/js/shopping-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/confirm',\n    'jquery-ui-modules/widget',\n    'mage/translate'\n], function ($, confirm) {\n    'use strict';\n\n    $.widget('mage.shoppingCart', {\n        /** @inheritdoc */\n        _create: function () {\n            var items, i, reload;\n\n            $(this.options.emptyCartButton).on('click', $.proxy(function () {\n                this._confirmClearCart();\n            }, this));\n            items = $.find('[data-role=\"cart-item-qty\"]');\n\n            for (i = 0; i < items.length; i++) {\n                $(items[i]).on('keypress', $.proxy(function (event) { //eslint-disable-line no-loop-func\n                    var keyCode = event.keyCode ? event.keyCode : event.which;\n\n                    if (keyCode == 13) { //eslint-disable-line eqeqeq\n                        $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');\n                        $(this.options.updateCartActionContainer)\n                            .attr('name', 'update_cart_action').attr('value', 'update_qty');\n\n                    }\n                }, this));\n            }\n            $(this.options.continueShoppingButton).on('click', $.proxy(function () {\n                location.href = this.options.continueShoppingUrl;\n            }, this));\n\n            $(document).on('ajax:removeFromCart', $.proxy(function () {\n                reload = true;\n                $('div.block.block-minicart').on('dropdowndialogclose', $.proxy(function () {\n                    if (reload === true) {\n                        location.reload();\n                        reload = false;\n                    }\n                    $('div.block.block-minicart').off('dropdowndialogclose');\n                }));\n            }, this));\n            $(document).on('ajax:updateItemQty', $.proxy(function () {\n                reload = true;\n                $('div.block.block-minicart').on('dropdowndialogclose', $.proxy(function () {\n                    if (reload === true) {\n                        location.reload();\n                        reload = false;\n                    }\n                    $('div.block.block-minicart').off('dropdowndialogclose');\n                }));\n            }, this));\n        },\n\n        /**\n         * Display confirmation modal for clearing the cart\n         * @private\n         */\n        _confirmClearCart: function () {\n            var self = this;\n\n            confirm({\n                content: $.mage.__('Are you sure you want to remove all items from your shopping cart?'),\n                actions: {\n                    /**\n                     * Confirmation modal handler to execute clear cart action\n                     */\n                    confirm: function () {\n                        self.clearCart();\n                    }\n                }\n            });\n        },\n\n        /**\n         * Prepares the form and submit to clear the cart\n         * @public\n         */\n        clearCart: function () {\n            $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');\n            $(this.options.updateCartActionContainer)\n                .attr('name', 'update_cart_action').attr('value', 'empty_cart');\n\n            if ($(this.options.emptyCartButton).parents('form').length > 0) {\n                $(this.options.emptyCartButton).parents('form').trigger('submit');\n            }\n        }\n    });\n\n    return $.mage.shoppingCart;\n});\n","Magento_Checkout/js/checkout-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'rjsResolver'\n], function (resolver) {\n    'use strict';\n\n    /**\n     * Removes provided loader element from DOM.\n     *\n     * @param {HTMLElement} $loader - Loader DOM element.\n     */\n    function hideLoader($loader) {\n        $loader.parentNode.removeChild($loader);\n    }\n\n    /**\n     * Initializes assets loading process listener.\n     *\n     * @param {Object} config - Optional configuration\n     * @param {HTMLElement} $loader - Loader DOM element.\n     */\n    function init(config, $loader) {\n        resolver(hideLoader.bind(null, $loader));\n    }\n\n    return init;\n});\n","Magento_Checkout/js/checkout-data.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Checkout adapter for customer data storage\n *\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Customer/js/customer-data',\n    'mageUtils',\n    'jquery/jquery-storageapi'\n], function ($, storage, utils) {\n    'use strict';\n\n    var cacheKey = 'checkout-data',\n\n        /**\n         * @param {Object} data\n         */\n        saveData = function (data) {\n            storage.set(cacheKey, data);\n        },\n\n        /**\n         * @return {*}\n         */\n        initData = function () {\n            return {\n                'selectedShippingAddress': null, //Selected shipping address pulled from persistence storage\n                'shippingAddressFromData': null, //Shipping address pulled from persistence storage\n                'newCustomerShippingAddress': null, //Shipping address pulled from persistence storage for customer\n                'selectedShippingRate': null, //Shipping rate pulled from persistence storage\n                'selectedPaymentMethod': null, //Payment method pulled from persistence storage\n                'selectedBillingAddress': null, //Selected billing address pulled from persistence storage\n                'billingAddressFromData': null, //Billing address pulled from persistence storage\n                'newCustomerBillingAddress': null //Billing address pulled from persistence storage for new customer\n            };\n        },\n\n        /**\n         * @return {*}\n         */\n        getData = function () {\n            var data = storage.get(cacheKey)();\n\n            if ($.isEmptyObject(data)) {\n                data = $.initNamespaceStorage('mage-cache-storage').localStorage.get(cacheKey);\n\n                if ($.isEmptyObject(data)) {\n                    data = initData();\n                    saveData(data);\n                }\n            }\n\n            return data;\n        };\n\n    return {\n        /**\n         * Setting the selected shipping address pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setSelectedShippingAddress: function (data) {\n            var obj = getData();\n\n            obj.selectedShippingAddress = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the selected shipping address from persistence storage\n         *\n         * @return {*}\n         */\n        getSelectedShippingAddress: function () {\n            return getData().selectedShippingAddress;\n        },\n\n        /**\n         * Setting the shipping address pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setShippingAddressFromData: function (data) {\n            var obj = getData();\n\n            obj.shippingAddressFromData = utils.filterFormData(data);\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the shipping address from persistence storage\n         *\n         * @return {*}\n         */\n        getShippingAddressFromData: function () {\n            return getData().shippingAddressFromData;\n        },\n\n        /**\n         * Setting the shipping address pulled from persistence storage for new customer\n         *\n         * @param {Object} data\n         */\n        setNewCustomerShippingAddress: function (data) {\n            var obj = getData();\n\n            obj.newCustomerShippingAddress = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the shipping address from persistence storage for new customer\n         *\n         * @return {*}\n         */\n        getNewCustomerShippingAddress: function () {\n            return getData().newCustomerShippingAddress;\n        },\n\n        /**\n         * Setting the selected shipping rate pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setSelectedShippingRate: function (data) {\n            var obj = getData();\n\n            obj.selectedShippingRate = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the selected shipping rate from local storage\n         *\n         * @return {*}\n         */\n        getSelectedShippingRate: function () {\n            return getData().selectedShippingRate;\n        },\n\n        /**\n         * Setting the selected payment method pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setSelectedPaymentMethod: function (data) {\n            var obj = getData();\n\n            obj.selectedPaymentMethod = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the payment method from persistence storage\n         *\n         * @return {*}\n         */\n        getSelectedPaymentMethod: function () {\n            return getData().selectedPaymentMethod;\n        },\n\n        /**\n         * Setting the selected billing address pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setSelectedBillingAddress: function (data) {\n            var obj = getData();\n\n            obj.selectedBillingAddress = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the selected billing address from persistence storage\n         *\n         * @return {*}\n         */\n        getSelectedBillingAddress: function () {\n            return getData().selectedBillingAddress;\n        },\n\n        /**\n         * Setting the billing address pulled from persistence storage\n         *\n         * @param {Object} data\n         */\n        setBillingAddressFromData: function (data) {\n            var obj = getData();\n\n            obj.billingAddressFromData = utils.filterFormData(data);\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the billing address from persistence storage\n         *\n         * @return {*}\n         */\n        getBillingAddressFromData: function () {\n            return getData().billingAddressFromData;\n        },\n\n        /**\n         * Setting the billing address pulled from persistence storage for new customer\n         *\n         * @param {Object} data\n         */\n        setNewCustomerBillingAddress: function (data) {\n            var obj = getData();\n\n            obj.newCustomerBillingAddress = data;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the billing address from persistence storage for new customer\n         *\n         * @return {*}\n         */\n        getNewCustomerBillingAddress: function () {\n            return getData().newCustomerBillingAddress;\n        },\n\n        /**\n         * Pulling the email address from persistence storage\n         *\n         * @return {*}\n         */\n        getValidatedEmailValue: function () {\n            var obj = getData();\n\n            return obj.validatedEmailValue ? obj.validatedEmailValue : '';\n        },\n\n        /**\n         * Setting the email address pulled from persistence storage\n         *\n         * @param {String} email\n         */\n        setValidatedEmailValue: function (email) {\n            var obj = getData();\n\n            obj.validatedEmailValue = email;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the email input field value from persistence storage\n         *\n         * @return {*}\n         */\n        getInputFieldEmailValue: function () {\n            var obj = getData();\n\n            return obj.inputFieldEmailValue ? obj.inputFieldEmailValue : '';\n        },\n\n        /**\n         * Setting the email input field value pulled from persistence storage\n         *\n         * @param {String} email\n         */\n        setInputFieldEmailValue: function (email) {\n            var obj = getData();\n\n            obj.inputFieldEmailValue = email;\n            saveData(obj);\n        },\n\n        /**\n         * Pulling the checked email value from persistence storage\n         *\n         * @return {*}\n         */\n        getCheckedEmailValue: function () {\n            var obj = getData();\n\n            return obj.checkedEmailValue ? obj.checkedEmailValue : '';\n        },\n\n        /**\n         * Setting the checked email value pulled from persistence storage\n         *\n         * @param {String} email\n         */\n        setCheckedEmailValue: function (email) {\n            var obj = getData();\n\n            obj.checkedEmailValue = email;\n            saveData(obj);\n        }\n    };\n});\n","Magento_Checkout/js/proceed-to-checkout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Customer/js/model/authentication-popup',\n    'Magento_Customer/js/customer-data'\n], function ($, authenticationPopup, customerData) {\n    'use strict';\n\n    return function (config, element) {\n        $(element).on('click', function (event) {\n            var cart = customerData.get('cart'),\n                customer = customerData.get('customer');\n\n            event.preventDefault();\n\n            if (!customer().firstname && cart().isGuestCheckoutAllowed === false) {\n                authenticationPopup.showModal();\n\n                return false;\n            }\n            $(element).attr('disabled', true);\n            location.href = config.checkoutUrl;\n        });\n\n    };\n});\n","Magento_Checkout/js/catalog-add-to-cart-mixin.js":"define([\"jquery\"], function($){\n  return function(config, element){\n    var minicart = $(element);\n    minicart.on('contentLoading', function () {\n      minicart.on('contentUpdated', function () {\n        minicart.find('[data-role=\"dropdownDialog\"]').dropdownDialog(\"open\");\n      });\n    });\n  }\n});\n","Magento_Checkout/js/model/default-post-code-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([], function () {\n    'use strict';\n\n    /**\n     * Define necessity of using default post code value\n     */\n    var useDefaultPostCode;\n\n    return {\n        /**\n         * Resolve default post code\n         *\n         * @returns {String|null}\n         */\n        resolve: function () {\n            return useDefaultPostCode ?  window.checkoutConfig.defaultPostcode : null;\n        },\n\n        /**\n         * Set state to useDefaultPostCode variable\n         *\n         * @param {Boolean} shouldUseDefaultPostCode\n         * @returns {underscore}\n         */\n        setUseDefaultPostCode: function (shouldUseDefaultPostCode) {\n            useDefaultPostCode = shouldUseDefaultPostCode;\n\n            return this;\n        }\n    };\n});\n","Magento_Checkout/js/model/payment-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/payment/method-list',\n    'Magento_Checkout/js/action/select-payment-method'\n], function (_, quote, methodList, selectPaymentMethod) {\n    'use strict';\n\n    /**\n    * Free method filter\n    * @param {Object} paymentMethod\n    * @return {Boolean}\n    */\n    var isFreePaymentMethod = function (paymentMethod) {\n            return paymentMethod.method === 'free';\n        },\n\n        /**\n         * Grabs the grand total from quote\n         * @return {Number}\n         */\n        getGrandTotal = function () {\n            return quote.totals()['grand_total'];\n        };\n\n    return {\n        isFreeAvailable: false,\n\n        /**\n         * Populate the list of payment methods\n         * @param {Array} methods\n         */\n        setPaymentMethods: function (methods) {\n            var freeMethod,\n                filteredMethods,\n                methodIsAvailable,\n                methodNames;\n\n            freeMethod = _.find(methods, isFreePaymentMethod);\n            this.isFreeAvailable = !!freeMethod;\n\n            if (freeMethod && getGrandTotal() <= 0) {\n                methods.splice(0, methods.length, freeMethod);\n                selectPaymentMethod(freeMethod);\n            }\n\n            filteredMethods = _.without(methods, freeMethod);\n\n            if (filteredMethods.length === 1) {\n                selectPaymentMethod(filteredMethods[0]);\n            } else if (quote.paymentMethod()) {\n                methodIsAvailable = methods.some(function (item) {\n                    return item.method === quote.paymentMethod().method;\n                });\n                //Unset selected payment method if not available\n                if (!methodIsAvailable) {\n                    selectPaymentMethod(null);\n                }\n            }\n\n            /**\n             * Overwrite methods with existing methods to preserve ko array references.\n             * This prevent ko from re-rendering those methods.\n             */\n            methodNames = _.pluck(methods, 'method');\n            _.map(methodList(), function (existingMethod) {\n                var existingMethodIndex = methodNames.indexOf(existingMethod.method);\n\n                if (existingMethodIndex !== -1) {\n                    methods[existingMethodIndex] = existingMethod;\n                }\n            });\n\n            methodList(methods);\n        },\n\n        /**\n         * Get the list of available payment methods.\n         * @return {Array}\n         */\n        getAvailablePaymentMethods: function () {\n            var allMethods = methodList().slice(),\n                grandTotalOverZero = getGrandTotal() > 0;\n\n            if (!this.isFreeAvailable) {\n                return allMethods;\n            }\n\n            if (grandTotalOverZero) {\n                return _.reject(allMethods, isFreePaymentMethod);\n            }\n\n            return _.filter(allMethods, isFreePaymentMethod);\n        }\n    };\n});\n","Magento_Checkout/js/model/default-validation-rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return {\n        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return {\n                'country_id': {\n                    'required': true\n                }\n            };\n        }\n    };\n});\n","Magento_Checkout/js/model/authentication-messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_Ui/js/model/messages'\n], function (ko, Messages) {\n    'use strict';\n\n    return new Messages();\n});\n","Magento_Checkout/js/model/full-screen-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'rjsResolver'\n], function ($, resolver) {\n    'use strict';\n\n    var containerId = '#checkout';\n\n    return {\n\n        /**\n         * Start full page loader action\n         */\n        startLoader: function () {\n            $(containerId).trigger('processStart');\n        },\n\n        /**\n         * Stop full page loader action\n         *\n         * @param {Boolean} [forceStop]\n         */\n        stopLoader: function (forceStop) {\n            var $elem = $(containerId),\n                stop = $elem.trigger.bind($elem, 'processStop'); //eslint-disable-line jquery-no-bind-unbind\n\n            forceStop ? stop() : resolver(stop);\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-rate-registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    var cache = [];\n\n    return {\n        /**\n         * @param {String} addressKey\n         * @return {*}\n         */\n        get: function (addressKey) {\n            if (cache[addressKey]) {\n                return cache[addressKey];\n            }\n\n            return false;\n        },\n\n        /**\n         * @param {String} addressKey\n         * @param {*} data\n         */\n        set: function (addressKey, data) {\n            cache[addressKey] = data;\n        }\n    };\n});\n","Magento_Checkout/js/model/customer-email-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Customer/js/model/customer',\n    'mage/validation'\n], function ($, customer) {\n    'use strict';\n\n    return {\n        /**\n         * Validate checkout agreements\n         *\n         * @returns {Boolean}\n         */\n        validate: function () {\n            var emailValidationResult = customer.isLoggedIn(),\n                loginFormSelector = 'form[data-role=email-with-possible-login]';\n\n            if (!customer.isLoggedIn()) {\n                $(loginFormSelector).validation();\n                emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());\n            }\n\n            return emailValidationResult;\n        }\n    };\n});\n","Magento_Checkout/js/model/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Customer/js/customer-data'\n], function (ko, quote, customerData) {\n    'use strict';\n\n    var quoteItems = ko.observable(quote.totals().items),\n        cartData = customerData.get('cart'),\n        quoteSubtotal = parseFloat(quote.totals().subtotal),\n        subtotalAmount = parseFloat(cartData().subtotalAmount);\n\n    quote.totals.subscribe(function (newValue) {\n        quoteItems(newValue.items);\n    });\n\n    if (!isNaN(subtotalAmount) && quoteSubtotal !== subtotalAmount && quoteSubtotal !== 0) {\n        customerData.reload(['cart'], false);\n    }\n\n    return {\n        totals: quote.totals,\n        isLoading: ko.observable(false),\n\n        /**\n         * @return {Function}\n         */\n        getItems: function () {\n            return quoteItems;\n        },\n\n        /**\n         * @param {*} code\n         * @return {*}\n         */\n        getSegment: function (code) {\n            var i, total;\n\n            if (!this.totals()) {\n                return null;\n            }\n\n            for (i in this.totals()['total_segments']) { //eslint-disable-line guard-for-in\n                total = this.totals()['total_segments'][i];\n\n                if (total.code == code) { //eslint-disable-line eqeqeq\n                    return total;\n                }\n            }\n\n            return null;\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-rates-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'ko',\n    './shipping-rates-validation-rules',\n    '../model/address-converter',\n    '../action/select-shipping-address',\n    './postcode-validator',\n    './default-validator',\n    'mage/translate',\n    'uiRegistry',\n    'Magento_Checkout/js/model/shipping-address/form-popup-state',\n    'Magento_Checkout/js/model/quote'\n], function (\n    $,\n    ko,\n    shippingRatesValidationRules,\n    addressConverter,\n    selectShippingAddress,\n    postcodeValidator,\n    defaultValidator,\n    $t,\n    uiRegistry,\n    formPopUpState\n) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig,\n        validators = [],\n        observedElements = [],\n        postcodeElements = [],\n        postcodeElementName = 'postcode';\n\n    validators.push(defaultValidator);\n\n    return {\n        validateAddressTimeout: 0,\n        validateZipCodeTimeout: 0,\n        validateDelay: 2000,\n\n        /**\n         * @param {String} carrier\n         * @param {Object} validator\n         */\n        registerValidator: function (carrier, validator) {\n            if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) {\n                validators.push(validator);\n            }\n        },\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validateAddressData: function (address) {\n            return validators.some(function (validator) {\n                return validator.validate(address);\n            });\n        },\n\n        /**\n         * Perform postponed binding for fieldset elements\n         *\n         * @param {String} formPath\n         */\n        initFields: function (formPath) {\n            var self = this,\n                elements = shippingRatesValidationRules.getObservableFields();\n\n            if ($.inArray(postcodeElementName, elements) === -1) {\n                // Add postcode field to observables if not exist for zip code validation support\n                elements.push(postcodeElementName);\n            }\n\n            $.each(elements, function (index, field) {\n                uiRegistry.async(formPath + '.' + field)(self.doElementBinding.bind(self));\n            });\n        },\n\n        /**\n         * Bind shipping rates request to form element\n         *\n         * @param {Object} element\n         * @param {Boolean} force\n         * @param {Number} delay\n         */\n        doElementBinding: function (element, force, delay) {\n            var observableFields = shippingRatesValidationRules.getObservableFields();\n\n            if (element && (observableFields.indexOf(element.index) !== -1 || force)) {\n                if (element.index !== postcodeElementName) {\n                    this.bindHandler(element, delay);\n                }\n            }\n\n            if (element.index === postcodeElementName) {\n                this.bindHandler(element, delay);\n                postcodeElements.push(element);\n            }\n        },\n\n        /**\n         * @param {*} elements\n         * @param {Boolean} force\n         * @param {Number} delay\n         */\n        bindChangeHandlers: function (elements, force, delay) {\n            var self = this;\n\n            $.each(elements, function (index, elem) {\n                self.doElementBinding(elem, force, delay);\n            });\n        },\n\n        /**\n         * @param {Object} element\n         * @param {Number} delay\n         */\n        bindHandler: function (element, delay) {\n            var self = this;\n\n            delay = typeof delay === 'undefined' ? self.validateDelay : delay;\n\n            if (element.component.indexOf('/group') !== -1) {\n                $.each(element.elems(), function (index, elem) {\n                    self.bindHandler(elem);\n                });\n            } else {\n                element.on('value', function () {\n                    clearTimeout(self.validateZipCodeTimeout);\n                    self.validateZipCodeTimeout = setTimeout(function () {\n                        if (element.index === postcodeElementName) {\n                            self.postcodeValidation(element);\n                        } else {\n                            $.each(postcodeElements, function (index, elem) {\n                                self.postcodeValidation(elem);\n                            });\n                        }\n                    }, delay);\n\n                    if (!formPopUpState.isVisible()) {\n                        clearTimeout(self.validateAddressTimeout);\n                        self.validateAddressTimeout = setTimeout(function () {\n                            self.validateFields();\n                        }, delay);\n                    }\n                });\n                observedElements.push(element);\n            }\n        },\n\n        /**\n         * @return {*}\n         */\n        postcodeValidation: function (postcodeElement) {\n            var countryId = $('select[name=\"country_id\"]:visible').val(),\n                validationResult,\n                warnMessage;\n\n            if (postcodeElement == null || postcodeElement.value() == null) {\n                return true;\n            }\n\n            postcodeElement.warn(null);\n            validationResult = postcodeValidator.validate(postcodeElement.value(), countryId);\n\n            if (!validationResult) {\n                warnMessage = $t('Provided Zip/Postal Code seems to be invalid.');\n\n                if (postcodeValidator.validatedPostCodeExample.length) {\n                    warnMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; ') + '. ';\n                }\n                warnMessage += $t('If you believe it is the right one you can ignore this notice.');\n                postcodeElement.warn(warnMessage);\n            }\n\n            return validationResult;\n        },\n\n        /**\n         * Convert form data to quote address and validate fields for shipping rates\n         */\n        validateFields: function () {\n            var addressFlat = addressConverter.formDataProviderToFlatData(\n                this.collectObservedData(),\n                'shippingAddress'\n                ),\n                address;\n\n            if (this.validateAddressData(addressFlat)) {\n                addressFlat = uiRegistry.get('checkoutProvider').shippingAddress;\n                address = addressConverter.formAddressDataToQuoteAddress(addressFlat);\n                selectShippingAddress(address);\n            }\n        },\n\n        /**\n         * Collect observed fields data to object\n         *\n         * @returns {*}\n         */\n        collectObservedData: function () {\n            var observedValues = {};\n\n            $.each(observedElements, function (index, field) {\n                observedValues[field.dataScope] = field.value();\n            });\n\n            return observedValues;\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-rate-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/shipping-rate-processor/new-address',\n    'Magento_Checkout/js/model/shipping-rate-processor/customer-address'\n], function (quote, defaultProcessor, customerAddressProcessor) {\n    'use strict';\n\n    var processors = {};\n\n    processors.default =  defaultProcessor;\n    processors['customer-address'] = customerAddressProcessor;\n\n    quote.shippingAddress.subscribe(function () {\n        var type = quote.shippingAddress().getType();\n\n        if (processors[type]) {\n            processors[type].getRates(quote.shippingAddress());\n        } else {\n            processors.default.getRates(quote.shippingAddress());\n        }\n    });\n\n    return {\n        /**\n         * @param {String} type\n         * @param {*} processor\n         */\n        registerProcessor: function (type, processor) {\n            processors[type] = processor;\n        }\n    };\n});\n","Magento_Checkout/js/model/place-order.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine(\n    [\n        'mage/storage',\n        'Magento_Checkout/js/model/error-processor',\n        'Magento_Checkout/js/model/full-screen-loader',\n        'Magento_Customer/js/customer-data',\n        'Magento_Checkout/js/model/payment/place-order-hooks',\n        'underscore'\n    ],\n    function (storage, errorProcessor, fullScreenLoader, customerData, hooks, _) {\n        'use strict';\n\n        return function (serviceUrl, payload, messageContainer) {\n            var headers = {}, redirectURL = '';\n\n            fullScreenLoader.startLoader();\n            _.each(hooks.requestModifiers, function (modifier) {\n                modifier(headers, payload);\n            });\n\n            return storage.post(\n                serviceUrl, JSON.stringify(payload), true, 'application/json', headers\n            ).fail(\n                function (response) {\n                    errorProcessor.process(response, messageContainer);\n                    redirectURL = response.getResponseHeader('errorRedirectAction');\n\n                    if (redirectURL) {\n                        setTimeout(function () {\n                            errorProcessor.redirectTo(redirectURL);\n                        }, 3000);\n                    }\n                }\n            ).done(\n                function (response) {\n                    var clearData = {\n                        'selectedShippingAddress': null,\n                        'shippingAddressFromData': null,\n                        'newCustomerShippingAddress': null,\n                        'selectedShippingRate': null,\n                        'selectedPaymentMethod': null,\n                        'selectedBillingAddress': null,\n                        'billingAddressFromData': null,\n                        'newCustomerBillingAddress': null\n                    };\n\n                    if (response.responseType !== 'error') {\n                        customerData.set('checkout-data', clearData);\n                    }\n                }\n            ).always(\n                function () {\n                    fullScreenLoader.stopLoader();\n                    _.each(hooks.afterRequestListeners, function (listener) {\n                        listener();\n                    });\n                }\n            );\n        };\n    }\n);\n","Magento_Checkout/js/model/postcode-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'mageUtils'\n], function (utils) {\n    'use strict';\n\n    return {\n        validatedPostCodeExample: [],\n\n        /**\n         * @param {*} postCode\n         * @param {*} countryId\n         * @param {Array} postCodesPatterns\n         * @return {Boolean}\n         */\n        validate: function (postCode, countryId, postCodesPatterns) {\n            var pattern, regex,\n                patterns = postCodesPatterns ? postCodesPatterns[countryId] :\n                    window.checkoutConfig.postCodes[countryId];\n\n            this.validatedPostCodeExample = [];\n\n            if (!utils.isEmpty(postCode) && !utils.isEmpty(patterns)) {\n                for (pattern in patterns) {\n                    if (patterns.hasOwnProperty(pattern)) { //eslint-disable-line max-depth\n                        this.validatedPostCodeExample.push(patterns[pattern].example);\n                        regex = new RegExp(patterns[pattern].pattern);\n\n                        if (regex.test(postCode)) { //eslint-disable-line max-depth\n                            return true;\n                        }\n                    }\n                }\n\n                return false;\n            }\n\n            return true;\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-save-processor.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Checkout/js/model/shipping-save-processor/default'\n], function (defaultProcessor) {\n    'use strict';\n\n    var processors = {};\n\n    processors['default'] =  defaultProcessor;\n\n    return {\n        /**\n         * @param {String} type\n         * @param {*} processor\n         */\n        registerProcessor: function (type, processor) {\n            processors[type] = processor;\n        },\n\n        /**\n         * @param {String} type\n         * @return {Array}\n         */\n        saveShippingInformation: function (type) {\n            var rates = [];\n\n            if (processors[type]) {\n                rates = processors[type].saveShippingInformation();\n            } else {\n                rates = processors['default'].saveShippingInformation();\n            }\n\n            return rates;\n        }\n    };\n});\n","Magento_Checkout/js/model/sidebar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return {\n        popUp: false,\n\n        /**\n         * @param {Object} popUp\n         */\n        setPopup: function (popUp) {\n            this.popUp = popUp;\n        },\n\n        /**\n         * Show popup.\n         */\n        show: function () {\n            if (this.popUp) {\n                this.popUp.modal('openModal');\n            }\n        },\n\n        /**\n         * Hide popup.\n         */\n        hide: function () {\n            if (this.popUp) {\n                this.popUp.modal('closeModal');\n            }\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-rates-validation-rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(['jquery'], function ($) {\n    'use strict';\n\n    var ratesRules = {},\n        checkoutConfig = window.checkoutConfig;\n\n    return {\n        /**\n         * @param {String} carrier\n         * @param {Object} rules\n         */\n        registerRules: function (carrier, rules) {\n            if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) {\n                ratesRules[carrier] = rules.getRules();\n            }\n        },\n\n        /**\n         * @return {Object}\n         */\n        getRules: function () {\n            return ratesRules;\n        },\n\n        /**\n         * @return {Array}\n         */\n        getObservableFields: function () {\n            var self = this,\n                observableFields = [];\n\n            $.each(self.getRules(), function (carrier, fields) {\n                $.each(fields, function (field) {\n                    if (observableFields.indexOf(field) === -1) {\n                        observableFields.push(field);\n                    }\n                });\n            });\n\n            return observableFields;\n        }\n    };\n});\n","Magento_Checkout/js/model/default-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils',\n    './default-validation-rules',\n    'mage/translate'\n], function ($, utils, validationRules, $t) {\n    'use strict';\n\n    return {\n        validationErrors: [],\n\n        /**\n         * @param {Object} address\n         * @return {Boolean}\n         */\n        validate: function (address) {\n            var self = this;\n\n            this.validationErrors = [];\n            $.each(validationRules.getRules(), function (field, rule) {\n                var message;\n\n                if (rule.required && utils.isEmpty(address[field])) {\n                    message = $t('Field ') + field + $t(' is required.');\n\n                    self.validationErrors.push(message);\n                }\n            });\n\n            return !this.validationErrors.length;\n        }\n    };\n});\n","Magento_Checkout/js/model/resource-url-manager.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Customer/js/model/customer',\n    'Magento_Checkout/js/model/url-builder',\n    'mageUtils'\n], function (customer, urlBuilder, utils) {\n        'use strict';\n\n        return {\n            /**\n             * @param {Object} quote\n             * @return {*}\n             */\n            getUrlForTotalsEstimationForNewAddress: function (quote) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            cartId: quote.getQuoteId()\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/:cartId/totals-information',\n                        'customer': '/carts/mine/totals-information'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {Object} quote\n             * @return {*}\n             */\n            getUrlForEstimationShippingMethodsForNewAddress: function (quote) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            quoteId: quote.getQuoteId()\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/:quoteId/estimate-shipping-methods',\n                        'customer': '/carts/mine/estimate-shipping-methods'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {Object} quote\n             * @return {*}\n             */\n            getUrlForEstimationShippingMethodsByAddressId: function (quote) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            quoteId: quote.getQuoteId()\n                        } : {},\n                    urls = {\n                        'default': '/carts/mine/estimate-shipping-methods-by-address-id'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {String} couponCode\n             * @param {String} quoteId\n             * @return {*}\n             */\n            getApplyCouponUrl: function (couponCode, quoteId) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            quoteId: quoteId\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/' + quoteId + '/coupons/' + encodeURIComponent(couponCode),\n                        'customer': '/carts/mine/coupons/' + encodeURIComponent(couponCode)\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {String} quoteId\n             * @return {*}\n             */\n            getCancelCouponUrl: function (quoteId) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            quoteId: quoteId\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/' + quoteId + '/coupons/',\n                        'customer': '/carts/mine/coupons/'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {Object} quote\n             * @return {*}\n             */\n            getUrlForCartTotals: function (quote) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            quoteId: quote.getQuoteId()\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/:quoteId/totals',\n                        'customer': '/carts/mine/totals'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * @param {Object} quote\n             * @return {*}\n             */\n            getUrlForSetShippingInformation: function (quote) {\n                var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n                        {\n                            cartId: quote.getQuoteId()\n                        } : {},\n                    urls = {\n                        'guest': '/guest-carts/:cartId/shipping-information',\n                        'customer': '/carts/mine/shipping-information'\n                    };\n\n                return this.getUrl(urls, params);\n            },\n\n            /**\n             * Get url for service.\n             *\n             * @param {*} urls\n             * @param {*} urlParams\n             * @return {String|*}\n             */\n            getUrl: function (urls, urlParams) {\n                var url;\n\n                if (utils.isEmpty(urls)) {\n                    return 'Provided service call does not exist.';\n                }\n\n                if (!utils.isEmpty(urls['default'])) {\n                    url = urls['default'];\n                } else {\n                    url = urls[this.getCheckoutMethod()];\n                }\n\n                return urlBuilder.createUrl(url, urlParams);\n            },\n\n            /**\n             * @return {String}\n             */\n            getCheckoutMethod: function () {\n                return customer.isLoggedIn() ? 'customer' : 'guest';\n            }\n        };\n    }\n);\n","Magento_Checkout/js/model/checkout-data-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Checkout adapter for customer data storage\n */\ndefine([\n    'Magento_Customer/js/model/address-list',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/action/create-shipping-address',\n    'Magento_Checkout/js/action/select-shipping-address',\n    'Magento_Checkout/js/action/select-shipping-method',\n    'Magento_Checkout/js/model/payment-service',\n    'Magento_Checkout/js/action/select-payment-method',\n    'Magento_Checkout/js/model/address-converter',\n    'Magento_Checkout/js/action/select-billing-address',\n    'Magento_Checkout/js/action/create-billing-address',\n    'underscore'\n], function (\n    addressList,\n    quote,\n    checkoutData,\n    createShippingAddress,\n    selectShippingAddress,\n    selectShippingMethodAction,\n    paymentService,\n    selectPaymentMethodAction,\n    addressConverter,\n    selectBillingAddress,\n    createBillingAddress,\n    _\n) {\n    'use strict';\n\n    var isBillingAddressResolvedFromBackend = false;\n\n    return {\n\n        /**\n         * Resolve estimation address. Used local storage\n         */\n        resolveEstimationAddress: function () {\n            var address;\n\n            if (quote.isVirtual()) {\n                if (checkoutData.getBillingAddressFromData()) {\n                    address = addressConverter.formAddressDataToQuoteAddress(\n                        checkoutData.getBillingAddressFromData()\n                    );\n                    selectBillingAddress(address);\n                } else {\n                    this.resolveBillingAddress();\n                }\n            } else if (checkoutData.getShippingAddressFromData()) {\n                address = addressConverter.formAddressDataToQuoteAddress(checkoutData.getShippingAddressFromData());\n                selectShippingAddress(address);\n            } else {\n                this.resolveShippingAddress();\n            }\n        },\n\n        /**\n         * Resolve shipping address. Used local storage\n         */\n        resolveShippingAddress: function () {\n            var newCustomerShippingAddress;\n\n            if (!checkoutData.getShippingAddressFromData() &&\n                window.checkoutConfig.shippingAddressFromData\n            ) {\n                checkoutData.setShippingAddressFromData(window.checkoutConfig.shippingAddressFromData);\n            }\n\n            newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress();\n\n            if (newCustomerShippingAddress) {\n                createShippingAddress(newCustomerShippingAddress);\n            }\n            this.applyShippingAddress();\n        },\n\n        /**\n         * Apply resolved estimated address to quote\n         *\n         * @param {Object} isEstimatedAddress\n         */\n        applyShippingAddress: function (isEstimatedAddress) {\n            var address,\n                shippingAddress,\n                isConvertAddress;\n\n            if (addressList().length === 0) {\n                address = addressConverter.formAddressDataToQuoteAddress(\n                    checkoutData.getShippingAddressFromData()\n                );\n                selectShippingAddress(address);\n            }\n            shippingAddress = quote.shippingAddress();\n            isConvertAddress = isEstimatedAddress || false;\n\n            if (!shippingAddress) {\n                shippingAddress = this.getShippingAddressFromCustomerAddressList();\n\n                if (shippingAddress) {\n                    selectShippingAddress(\n                        isConvertAddress ?\n                            addressConverter.addressToEstimationAddress(shippingAddress)\n                            : shippingAddress\n                    );\n                }\n            }\n        },\n\n        /**\n         * @param {Object} ratesData\n         */\n        resolveShippingRates: function (ratesData) {\n            var selectedShippingRate = checkoutData.getSelectedShippingRate(),\n                availableRate = false;\n\n            if (ratesData.length === 1 && !quote.shippingMethod()) {\n                //set shipping rate if we have only one available shipping rate\n                selectShippingMethodAction(ratesData[0]);\n\n                return;\n            }\n\n            if (quote.shippingMethod()) {\n                availableRate = _.find(ratesData, function (rate) {\n                    return rate['carrier_code'] == quote.shippingMethod()['carrier_code'] && //eslint-disable-line\n                        rate['method_code'] == quote.shippingMethod()['method_code']; //eslint-disable-line eqeqeq\n                });\n            }\n\n            if (!availableRate && selectedShippingRate) {\n                availableRate = _.find(ratesData, function (rate) {\n                    return rate['carrier_code'] + '_' + rate['method_code'] === selectedShippingRate;\n                });\n            }\n\n            if (!availableRate && window.checkoutConfig.selectedShippingMethod) {\n                availableRate = _.find(ratesData, function (rate) {\n                    var selectedShippingMethod = window.checkoutConfig.selectedShippingMethod;\n\n                    return rate['carrier_code'] == selectedShippingMethod['carrier_code'] && //eslint-disable-line\n                        rate['method_code'] == selectedShippingMethod['method_code']; //eslint-disable-line eqeqeq\n                });\n            }\n\n            //Unset selected shipping method if not available\n            if (!availableRate) {\n                selectShippingMethodAction(null);\n            } else {\n                selectShippingMethodAction(availableRate);\n            }\n        },\n\n        /**\n         * Resolve payment method. Used local storage\n         */\n        resolvePaymentMethod: function () {\n            var availablePaymentMethods = paymentService.getAvailablePaymentMethods(),\n                selectedPaymentMethod = checkoutData.getSelectedPaymentMethod();\n\n            if (selectedPaymentMethod) {\n                availablePaymentMethods.some(function (payment) {\n                    if (payment.method == selectedPaymentMethod) { //eslint-disable-line eqeqeq\n                        selectPaymentMethodAction(payment);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Resolve billing address. Used local storage\n         */\n        resolveBillingAddress: function () {\n            var selectedBillingAddress,\n                newCustomerBillingAddressData;\n\n            selectedBillingAddress = checkoutData.getSelectedBillingAddress();\n            newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress();\n\n            if (selectedBillingAddress) {\n                if (selectedBillingAddress === 'new-customer-billing-address' && newCustomerBillingAddressData) {\n                    selectBillingAddress(createBillingAddress(newCustomerBillingAddressData));\n                } else {\n                    addressList.some(function (address) {\n                        if (selectedBillingAddress === address.getKey()) {\n                            selectBillingAddress(address);\n                        }\n                    });\n                }\n            } else {\n                this.applyBillingAddress();\n            }\n\n            if (!isBillingAddressResolvedFromBackend &&\n                !checkoutData.getBillingAddressFromData() &&\n                !_.isEmpty(window.checkoutConfig.billingAddressFromData) &&\n                !quote.billingAddress()\n            ) {\n                if (window.checkoutConfig.isBillingAddressFromDataValid === true) {\n                    selectBillingAddress(createBillingAddress(window.checkoutConfig.billingAddressFromData));\n                } else {\n                    checkoutData.setBillingAddressFromData(window.checkoutConfig.billingAddressFromData);\n                }\n                isBillingAddressResolvedFromBackend = true;\n            }\n        },\n\n        /**\n         * Apply resolved billing address to quote\n         */\n        applyBillingAddress: function () {\n            var shippingAddress,\n                isBillingAddressInitialized;\n\n            if (quote.billingAddress()) {\n                selectBillingAddress(quote.billingAddress());\n\n                return;\n            }\n\n            if (quote.isVirtual() || !quote.billingAddress()) {\n                isBillingAddressInitialized = addressList.some(function (addrs) {\n                    if (addrs.isDefaultBilling()) {\n                        selectBillingAddress(addrs);\n\n                        return true;\n                    }\n\n                    return false;\n                });\n            }\n\n            shippingAddress = quote.shippingAddress();\n\n            if (!isBillingAddressInitialized &&\n                shippingAddress &&\n                shippingAddress.canUseForBilling() &&\n                (shippingAddress.isDefaultShipping() || !quote.isVirtual())\n            ) {\n                //set billing address same as shipping by default if it is not empty\n                selectBillingAddress(quote.shippingAddress());\n            }\n        },\n\n        /**\n         * Get shipping address from address list\n         *\n         * @return {Object|null}\n         */\n        getShippingAddressFromCustomerAddressList: function () {\n            var shippingAddress = _.find(\n                    addressList(),\n                    function (address) {\n                        return checkoutData.getSelectedShippingAddress() == address.getKey() //eslint-disable-line\n                    }\n                );\n\n            if (!shippingAddress) {\n                shippingAddress = _.find(\n                    addressList(),\n                    function (address) {\n                        return address.isDefaultShipping();\n                    }\n                );\n            }\n\n            if (!shippingAddress && addressList().length === 1) {\n                shippingAddress = addressList()[0];\n            }\n\n            return shippingAddress;\n        }\n    };\n});\n","Magento_Checkout/js/model/billing-address-postcode-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n           'jquery',\n           'Magento_Checkout/js/model/postcode-validator',\n           'mage/translate',\n           'uiRegistry'\n       ], function (\n    $,\n    postcodeValidator,\n    $t,\n    uiRegistry\n) {\n    'use strict';\n\n    var postcodeElementName = 'postcode';\n\n    return {\n        validateZipCodeTimeout: 0,\n        validateDelay: 2000,\n\n        /**\n         * Perform postponed binding for fieldset elements\n         *\n         * @param {String} formPath\n         */\n        initFields: function (formPath) {\n            var self = this;\n\n            uiRegistry.async(formPath + '.' + postcodeElementName)(self.bindHandler.bind(self));\n        },\n\n        /**\n         * @param {Object} element\n         * @param {Number} delay\n         */\n        bindHandler: function (element, delay) {\n            var self = this;\n\n            delay = typeof delay === 'undefined' ? self.validateDelay : delay;\n\n            element.on('value', function () {\n                clearTimeout(self.validateZipCodeTimeout);\n                self.validateZipCodeTimeout = setTimeout(function () {\n                    self.postcodeValidation(element);\n                }, delay);\n            });\n        },\n\n        /**\n         * @param {Object} postcodeElement\n         * @return {*}\n         */\n        postcodeValidation: function (postcodeElement) {\n            var countryId = $('select[name=\"country_id\"]:visible').val(),\n                validationResult,\n                warnMessage;\n\n            if (postcodeElement == null || postcodeElement.value() == null) {\n                return true;\n            }\n\n            postcodeElement.warn(null);\n            validationResult = postcodeValidator.validate(postcodeElement.value(), countryId);\n\n            if (!validationResult) {\n                warnMessage = $t('Provided Zip/Postal Code seems to be invalid.');\n\n                if (postcodeValidator.validatedPostCodeExample.length) {\n                    warnMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; ') + '. ';\n                }\n                warnMessage += $t('If you believe it is the right one you can ignore this notice.');\n                postcodeElement.warn(warnMessage);\n            }\n\n            return validationResult;\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_Checkout/js/model/checkout-data-resolver'\n], function (ko, checkoutDataResolver) {\n    'use strict';\n\n    var shippingRates = ko.observableArray([]);\n\n    return {\n        isLoading: ko.observable(false),\n\n        /**\n         * Set shipping rates\n         *\n         * @param {*} ratesData\n         */\n        setShippingRates: function (ratesData) {\n            shippingRates(ratesData);\n            shippingRates.valueHasMutated();\n            checkoutDataResolver.resolveShippingRates(ratesData);\n        },\n\n        /**\n         * Get shipping rates\n         *\n         * @returns {*}\n         */\n        getShippingRates: function () {\n            return shippingRates;\n        }\n    };\n});\n","Magento_Checkout/js/model/url-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery'], function ($) {\n    'use strict';\n\n    return {\n        method: 'rest',\n        storeCode: window.checkoutConfig.storeCode,\n        version: 'V1',\n        serviceUrl: ':method/:storeCode/:version',\n\n        /**\n         * @param {String} url\n         * @param {Object} params\n         * @return {*}\n         */\n        createUrl: function (url, params) {\n            var completeUrl = this.serviceUrl + url;\n\n            return this.bindParams(completeUrl, params);\n        },\n\n        /**\n         * @param {String} url\n         * @param {Object} params\n         * @return {*}\n         */\n        bindParams: function (url, params) {\n            var urlParts;\n\n            params.method = this.method;\n            params.storeCode = this.storeCode;\n            params.version = this.version;\n\n            urlParts = url.split('/');\n            urlParts = urlParts.filter(Boolean);\n\n            $.each(urlParts, function (key, part) {\n                part = part.replace(':', '');\n\n                if (params[part] != undefined) { //eslint-disable-line eqeqeq\n                    urlParts[key] = params[part];\n                }\n            });\n\n            return urlParts.join('/');\n        }\n    };\n});\n","Magento_Checkout/js/model/address-converter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Checkout/js/model/new-customer-address',\n    'Magento_Customer/js/customer-data',\n    'mage/utils/objects',\n    'underscore'\n], function ($, address, customerData, mageUtils, _) {\n    'use strict';\n\n    var countryData = customerData.get('directory-data');\n\n    return {\n        /**\n         * Convert address form data to Address object\n         *\n         * @param {Object} formData\n         * @returns {Object}\n         */\n        formAddressDataToQuoteAddress: function (formData) {\n            // clone address form data to new object\n            var addressData = $.extend(true, {}, formData),\n                region,\n                regionName = addressData.region,\n                customAttributes;\n\n            if (mageUtils.isObject(addressData.street)) {\n                addressData.street = this.objectToArray(addressData.street);\n            }\n\n            addressData.region = {\n                'region_id': addressData['region_id'],\n                'region_code': addressData['region_code'],\n                region: regionName\n            };\n\n            if (addressData['region_id'] &&\n                countryData()[addressData['country_id']] &&\n                countryData()[addressData['country_id']].regions\n            ) {\n                region = countryData()[addressData['country_id']].regions[addressData['region_id']];\n\n                if (region) {\n                    addressData.region['region_id'] = addressData['region_id'];\n                    addressData.region['region_code'] = region.code;\n                    addressData.region.region = region.name;\n                }\n            } else if (\n                !addressData['region_id'] &&\n                countryData()[addressData['country_id']] &&\n                countryData()[addressData['country_id']].regions\n            ) {\n                addressData.region['region_code'] = '';\n                addressData.region.region = '';\n            }\n            delete addressData['region_id'];\n\n            if (addressData['custom_attributes']) {\n                addressData['custom_attributes'] = _.map(\n                    addressData['custom_attributes'],\n                    function (value, key) {\n                        customAttributes = {\n                            'attribute_code': key,\n                            'value': value\n                        };\n\n                        if (typeof value === 'boolean') {\n                            customAttributes = {\n                                'attribute_code': key,\n                                'value': value,\n                                'label': value === true ? 'Yes' : 'No'\n                            };\n                        }\n\n                        return customAttributes;\n                    }\n                );\n            }\n\n            return address(addressData);\n        },\n\n        /**\n         * Convert Address object to address form data.\n         *\n         * @param {Object} addrs\n         * @returns {Object}\n         */\n        quoteAddressToFormAddressData: function (addrs) {\n            var self = this,\n                output = {},\n                streetObject,\n                customAttributesObject;\n\n            $.each(addrs, function (key) {\n                if (addrs.hasOwnProperty(key) && typeof addrs[key] !== 'function') {\n                    output[self.toUnderscore(key)] = addrs[key];\n                }\n            });\n\n            if (Array.isArray(addrs.street)) {\n                streetObject = {};\n                addrs.street.forEach(function (value, index) {\n                    streetObject[index] = value;\n                });\n                output.street = streetObject;\n            }\n\n            //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n            if (Array.isArray(addrs.customAttributes)) {\n                customAttributesObject = {};\n                addrs.customAttributes.forEach(function (value) {\n                    customAttributesObject[value.attribute_code] = value.value;\n                });\n                output.custom_attributes = customAttributesObject;\n            }\n            //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n            return output;\n        },\n\n        /**\n         * @param {String} string\n         */\n        toUnderscore: function (string) {\n            return string.replace(/([A-Z])/g, function ($1) {\n                return '_' + $1.toLowerCase();\n            });\n        },\n\n        /**\n         * @param {Object} formProviderData\n         * @param {String} formIndex\n         * @return {Object}\n         */\n        formDataProviderToFlatData: function (formProviderData, formIndex) {\n            var addressData = {};\n\n            $.each(formProviderData, function (path, value) {\n                var pathComponents = path.split('.'),\n                    dataObject = {};\n\n                pathComponents.splice(pathComponents.indexOf(formIndex), 1);\n                pathComponents.reverse();\n                $.each(pathComponents, function (index, pathPart) {\n                    var parent = {};\n\n                    if (index == 0) { //eslint-disable-line eqeqeq\n                        dataObject[pathPart] = value;\n                    } else {\n                        parent[pathPart] = dataObject;\n                        dataObject = parent;\n                    }\n                });\n                $.extend(true, addressData, dataObject);\n            });\n\n            return addressData;\n        },\n\n        /**\n         * Convert object to array\n         * @param {Object} object\n         * @returns {Array}\n         */\n        objectToArray: function (object) {\n            var convertedArray = [];\n\n            $.each(object, function (key) {\n                return typeof object[key] === 'string' ? convertedArray.push(object[key]) : false;\n            });\n\n            return convertedArray.slice(0);\n        },\n\n        /**\n         * @param {Object} addrs\n         * @return {*|Object}\n         */\n        addressToEstimationAddress: function (addrs) {\n            var self = this,\n                estimatedAddressData = {};\n\n            $.each(addrs, function (key) {\n                estimatedAddressData[self.toUnderscore(key)] = addrs[key];\n            });\n\n            return this.formAddressDataToQuoteAddress(estimatedAddressData);\n        }\n    };\n});\n","Magento_Checkout/js/model/new-customer-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'Magento_Checkout/js/model/default-post-code-resolver'\n], function (_, DefaultPostCodeResolver) {\n    'use strict';\n\n    /**\n     * @param {Object} addressData\n     * Returns new address object\n     */\n    return function (addressData) {\n        var identifier = Date.now(),\n            countryId = addressData['country_id'] || addressData.countryId || window.checkoutConfig.defaultCountryId,\n            regionId;\n\n        if (addressData.region && addressData.region['region_id']) {\n            regionId = addressData.region['region_id'];\n        } else if (!addressData['region_id']) {\n            regionId = undefined;\n        } else if (\n            /* eslint-disable */\n            addressData['country_id'] && addressData['country_id'] == window.checkoutConfig.defaultCountryId ||\n            !addressData['country_id'] && countryId == window.checkoutConfig.defaultCountryId\n            /* eslint-enable */\n        ) {\n            regionId = window.checkoutConfig.defaultRegionId || undefined;\n        }\n\n        return {\n            email: addressData.email,\n            countryId: countryId,\n            regionId: regionId || addressData.regionId,\n            regionCode: addressData.region ? addressData.region['region_code'] : null,\n            region: addressData.region ? addressData.region.region : null,\n            customerId: addressData['customer_id'] || addressData.customerId,\n            street: addressData.street,\n            company: addressData.company,\n            telephone: addressData.telephone,\n            fax: addressData.fax,\n            postcode: addressData.postcode ? addressData.postcode : DefaultPostCodeResolver.resolve(),\n            city: addressData.city,\n            firstname: addressData.firstname,\n            lastname: addressData.lastname,\n            middlename: addressData.middlename,\n            prefix: addressData.prefix,\n            suffix: addressData.suffix,\n            vatId: addressData['vat_id'],\n            saveInAddressBook: addressData['save_in_address_book'],\n            customAttributes: addressData['custom_attributes'],\n            extensionAttributes: addressData['extension_attributes'],\n\n            /**\n             * @return {*}\n             */\n            isDefaultShipping: function () {\n                return addressData['default_shipping'];\n            },\n\n            /**\n             * @return {*}\n             */\n            isDefaultBilling: function () {\n                return addressData['default_billing'];\n            },\n\n            /**\n             * @return {String}\n             */\n            getType: function () {\n                return 'new-customer-address';\n            },\n\n            /**\n             * @return {String}\n             */\n            getKey: function () {\n                return this.getType();\n            },\n\n            /**\n             * @return {String}\n             */\n            getCacheKey: function () {\n                return this.getType() + identifier;\n            },\n\n            /**\n             * @return {Boolean}\n             */\n            isEditable: function () {\n                return true;\n            },\n\n            /**\n             * @return {Boolean}\n             */\n            canUseForBilling: function () {\n                return true;\n            }\n        };\n    };\n});\n","Magento_Checkout/js/model/quote.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'ko',\n    'underscore',\n    'domReady!'\n], function (ko, _) {\n    'use strict';\n\n    /**\n     * Get totals data from the extension attributes.\n     * @param {*} data\n     * @returns {*}\n     */\n    var proceedTotalsData = function (data) {\n            if (_.isObject(data) && _.isObject(data['extension_attributes'])) {\n                _.each(data['extension_attributes'], function (element, index) {\n                    data[index] = element;\n                });\n            }\n\n            return data;\n        },\n        billingAddress = ko.observable(null),\n        shippingAddress = ko.observable(null),\n        shippingMethod = ko.observable(null),\n        paymentMethod = ko.observable(null),\n        quoteData = window.checkoutConfig.quoteData,\n        basePriceFormat = window.checkoutConfig.basePriceFormat,\n        priceFormat = window.checkoutConfig.priceFormat,\n        storeCode = window.checkoutConfig.storeCode,\n        totalsData = proceedTotalsData(window.checkoutConfig.totalsData),\n        totals = ko.observable(totalsData),\n        collectedTotals = ko.observable({});\n\n    return {\n        totals: totals,\n        shippingAddress: shippingAddress,\n        shippingMethod: shippingMethod,\n        billingAddress: billingAddress,\n        paymentMethod: paymentMethod,\n        guestEmail: null,\n\n        /**\n         * @return {*}\n         */\n        getQuoteId: function () {\n            return quoteData['entity_id'];\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isVirtual: function () {\n            return !!Number(quoteData['is_virtual']);\n        },\n\n        /**\n         * @return {*}\n         */\n        getPriceFormat: function () {\n            return priceFormat;\n        },\n\n        /**\n         * @return {*}\n         */\n        getBasePriceFormat: function () {\n            return basePriceFormat;\n        },\n\n        /**\n         * @return {*}\n         */\n        getItems: function () {\n            return window.checkoutConfig.quoteItemData;\n        },\n\n        /**\n         *\n         * @return {*}\n         */\n        getTotals: function () {\n            return totals;\n        },\n\n        /**\n         * @param {Object} data\n         */\n        setTotals: function (data) {\n            data = proceedTotalsData(data);\n            totals(data);\n            this.setCollectedTotals('subtotal_with_discount', parseFloat(data['subtotal_with_discount']));\n        },\n\n        /**\n         * @param {*} paymentMethodCode\n         */\n        setPaymentMethod: function (paymentMethodCode) {\n            paymentMethod(paymentMethodCode);\n        },\n\n        /**\n         * @return {*}\n         */\n        getPaymentMethod: function () {\n            return paymentMethod;\n        },\n\n        /**\n         * @return {*}\n         */\n        getStoreCode: function () {\n            return storeCode;\n        },\n\n        /**\n         * @param {String} code\n         * @param {*} value\n         */\n        setCollectedTotals: function (code, value) {\n            var colTotals = collectedTotals();\n\n            colTotals[code] = value;\n            collectedTotals(colTotals);\n        },\n\n        /**\n         * @return {Number}\n         */\n        getCalculatedTotal: function () {\n            var total = 0.; //eslint-disable-line no-floating-decimal\n\n            _.each(collectedTotals(), function (value) {\n                total += value;\n            });\n\n            return total;\n        }\n    };\n});\n","Magento_Checkout/js/model/step-navigator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'ko'\n], function ($, ko) {\n    'use strict';\n\n    var steps = ko.observableArray();\n\n    return {\n        steps: steps,\n        stepCodes: [],\n        validCodes: [],\n\n        /**\n         * @return {Boolean}\n         */\n        handleHash: function () {\n            var hashString = window.location.hash.replace('#', ''),\n                isRequestedStepVisible;\n\n            if (hashString === '') {\n                return false;\n            }\n\n            if ($.inArray(hashString, this.validCodes) === -1) {\n                window.location.href = window.checkoutConfig.pageNotFoundUrl;\n\n                return false;\n            }\n\n            isRequestedStepVisible = steps.sort(this.sortItems).some(function (element) {\n                return (element.code == hashString || element.alias == hashString) && element.isVisible(); //eslint-disable-line\n            });\n\n            //if requested step is visible, then we don't need to load step data from server\n            if (isRequestedStepVisible) {\n                return false;\n            }\n\n            steps().sort(this.sortItems).forEach(function (element) {\n                if (element.code == hashString || element.alias == hashString) { //eslint-disable-line eqeqeq\n                    element.navigate(element);\n                } else {\n                    element.isVisible(false);\n                }\n\n            });\n\n            return false;\n        },\n\n        /**\n         * @param {String} code\n         * @param {*} alias\n         * @param {*} title\n         * @param {Function} isVisible\n         * @param {*} navigate\n         * @param {*} sortOrder\n         */\n        registerStep: function (code, alias, title, isVisible, navigate, sortOrder) {\n            var hash, active;\n\n            if ($.inArray(code, this.validCodes) !== -1) {\n                throw new DOMException('Step code [' + code + '] already registered in step navigator');\n            }\n\n            if (alias != null) {\n                if ($.inArray(alias, this.validCodes) !== -1) {\n                    throw new DOMException('Step code [' + alias + '] already registered in step navigator');\n                }\n                this.validCodes.push(alias);\n            }\n            this.validCodes.push(code);\n            steps.push({\n                code: code,\n                alias: alias != null ? alias : code,\n                title: title,\n                isVisible: isVisible,\n                navigate: navigate,\n                sortOrder: sortOrder\n            });\n            active = this.getActiveItemIndex();\n            steps.each(function (elem, index) {\n                if (active !== index) {\n                    elem.isVisible(false);\n                }\n            });\n            this.stepCodes.push(code);\n            hash = window.location.hash.replace('#', '');\n\n            if (hash != '' && hash != code) { //eslint-disable-line eqeqeq\n                //Force hiding of not active step\n                isVisible(false);\n            }\n        },\n\n        /**\n         * @param {Object} itemOne\n         * @param {Object} itemTwo\n         * @return {Number}\n         */\n        sortItems: function (itemOne, itemTwo) {\n            return itemOne.sortOrder > itemTwo.sortOrder ? 1 : -1;\n        },\n\n        /**\n         * @return {Number}\n         */\n        getActiveItemIndex: function () {\n            var activeIndex = 0;\n\n            steps().sort(this.sortItems).some(function (element, index) {\n                if (element.isVisible()) {\n                    activeIndex = index;\n\n                    return true;\n                }\n\n                return false;\n            });\n\n            return activeIndex;\n        },\n\n        /**\n         * @param {*} code\n         * @return {Boolean}\n         */\n        isProcessed: function (code) {\n            var activeItemIndex = this.getActiveItemIndex(),\n                sortedItems = steps().sort(this.sortItems),\n                requestedItemIndex = -1;\n\n            sortedItems.forEach(function (element, index) {\n                if (element.code == code) { //eslint-disable-line eqeqeq\n                    requestedItemIndex = index;\n                }\n            });\n\n            return activeItemIndex > requestedItemIndex;\n        },\n\n        /**\n         * @param {*} code\n         * @param {*} scrollToElementId\n         */\n        navigateTo: function (code, scrollToElementId) {\n            var sortedItems = steps().sort(this.sortItems),\n                bodyElem = $('body');\n\n            scrollToElementId = scrollToElementId || null;\n\n            if (!this.isProcessed(code)) {\n                return;\n            }\n            sortedItems.forEach(function (element) {\n                if (element.code == code) { //eslint-disable-line eqeqeq\n                    element.isVisible(true);\n                    bodyElem.animate({\n                        scrollTop: $('#' + code).offset().top\n                    }, 0, function () {\n                        window.location = window.checkoutConfig.checkoutUrl + '#' + code;\n                    });\n\n                    if (scrollToElementId && $('#' + scrollToElementId).length) {\n                        bodyElem.animate({\n                            scrollTop: $('#' + scrollToElementId).offset().top\n                        }, 0);\n                    }\n                } else {\n                    element.isVisible(false);\n                }\n\n            });\n        },\n\n        /**\n         * Sets window location hash.\n         *\n         * @param {String} hash\n         */\n        setHash: function (hash) {\n            window.location.hash = hash;\n        },\n\n        /**\n         * Next step.\n         */\n        next: function () {\n            var activeIndex = 0,\n                code;\n\n            steps().sort(this.sortItems).forEach(function (element, index) {\n                if (element.isVisible()) {\n                    element.isVisible(false);\n                    activeIndex = index;\n                }\n            });\n\n            if (steps().length > activeIndex + 1) {\n                code = steps()[activeIndex + 1].code;\n                steps()[activeIndex + 1].isVisible(true);\n                this.setHash(code);\n                document.body.scrollTop = document.documentElement.scrollTop = 0;\n            }\n        }\n    };\n});\n","Magento_Checkout/js/model/error-processor.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'mage/url',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate'\n], function (url, globalMessageList, $t) {\n    'use strict';\n\n    return {\n        /**\n         * @param {Object} response\n         * @param {Object} messageContainer\n         */\n        process: function (response, messageContainer) {\n            var error;\n\n            messageContainer = messageContainer || globalMessageList;\n\n            if (response.status == 401) { //eslint-disable-line eqeqeq\n                this.redirectTo(url.build('customer/account/login/'));\n            } else {\n                try {\n                    error = JSON.parse(response.responseText);\n                } catch (exception) {\n                    error = {\n                        message: $t('Something went wrong with your request. Please try again later.')\n                    };\n                }\n                messageContainer.addErrorMessage(error);\n            }\n        },\n\n        /**\n         * Method to redirect by requested URL.\n         */\n        redirectTo: function (redirectUrl) {\n            window.location.replace(redirectUrl);\n        }\n    };\n});\n","Magento_Checkout/js/model/cart/estimate-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/shipping-rate-processor/new-address',\n    'Magento_Checkout/js/model/cart/totals-processor/default',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Checkout/js/model/cart/cache',\n    'Magento_Customer/js/customer-data'\n], function (quote, defaultProcessor, totalsDefaultProvider, shippingService, cartCache, customerData) {\n    'use strict';\n\n    var rateProcessors = {},\n        totalsProcessors = {},\n\n        /**\n         * Estimate totals for shipping address and update shipping rates.\n         */\n        estimateTotalsAndUpdateRates = function () {\n            var type = quote.shippingAddress().getType();\n\n            if (\n                quote.isVirtual() ||\n                window.checkoutConfig.activeCarriers && window.checkoutConfig.activeCarriers.length === 0\n            ) {\n                // update totals block when estimated address was set\n                totalsProcessors['default'] = totalsDefaultProvider;\n                totalsProcessors[type] ?\n                    totalsProcessors[type].estimateTotals(quote.shippingAddress()) :\n                    totalsProcessors['default'].estimateTotals(quote.shippingAddress());\n            } else {\n                // check if user data not changed -> load rates from cache\n                if (!cartCache.isChanged('address', quote.shippingAddress()) &&\n                    !cartCache.isChanged('cartVersion', customerData.get('cart')()['data_id']) &&\n                    cartCache.get('rates')\n                ) {\n                    shippingService.setShippingRates(cartCache.get('rates'));\n\n                    return;\n                }\n\n                // update rates list when estimated address was set\n                rateProcessors['default'] = defaultProcessor;\n                rateProcessors[type] ?\n                    rateProcessors[type].getRates(quote.shippingAddress()) :\n                    rateProcessors['default'].getRates(quote.shippingAddress());\n\n                // save rates to cache after load\n                shippingService.getShippingRates().subscribe(function (rates) {\n                    cartCache.set('rates', rates);\n                });\n            }\n        },\n\n        /**\n         * Estimate totals for shipping address.\n         */\n        estimateTotalsShipping = function () {\n            totalsDefaultProvider.estimateTotals(quote.shippingAddress());\n        },\n\n        /**\n         * Estimate totals for billing address.\n         */\n        estimateTotalsBilling = function () {\n            var type = quote.billingAddress().getType();\n\n            if (quote.isVirtual()) {\n                // update totals block when estimated address was set\n                totalsProcessors['default'] = totalsDefaultProvider;\n                totalsProcessors[type] ?\n                    totalsProcessors[type].estimateTotals(quote.billingAddress()) :\n                    totalsProcessors['default'].estimateTotals(quote.billingAddress());\n            }\n        };\n\n    quote.shippingAddress.subscribe(estimateTotalsAndUpdateRates);\n    quote.shippingMethod.subscribe(estimateTotalsShipping);\n    quote.billingAddress.subscribe(estimateTotalsBilling);\n});\n","Magento_Checkout/js/model/cart/cache.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Cart adapter for customer data storage.\n * It stores cart data in customer data(localStorage) without saving on server.\n * Adapter is created for shipping rates and totals data caching. It eliminates unneeded calculations requests.\n */\ndefine([\n    'underscore',\n    'Magento_Customer/js/customer-data',\n    'mageUtils'\n], function (_, storage, utils) {\n    'use strict';\n\n    var cacheKey = 'cart-data',\n        cartData = {\n            totals: null,\n            address: null,\n            cartVersion: null,\n            shippingMethodCode: null,\n            shippingCarrierCode: null,\n            rates: null\n        },\n\n        /**\n         * Set data to local storage.\n         *\n         * @param {Object} checkoutData\n         */\n        setData = function (checkoutData) {\n            storage.set(cacheKey, checkoutData);\n        },\n\n        /**\n         * Get data from local storage.\n         *\n         * @param {String} [key]\n         * @returns {*}\n         */\n        getData = function (key) {\n            var data = key ? storage.get(cacheKey)()[key] : storage.get(cacheKey)();\n\n            if (_.isEmpty(storage.get(cacheKey)())) {\n                setData(utils.copy(cartData));\n            }\n\n            return data;\n        },\n\n        /**\n         * Build method name base on name, prefix and suffix.\n         *\n         * @param {String} name\n         * @param {String} prefix\n         * @param {String} suffix\n         * @return {String}\n         */\n        getMethodName = function (name, prefix, suffix) {\n            prefix = prefix || '';\n            suffix = suffix || '';\n\n            return prefix + name.charAt(0).toUpperCase() + name.slice(1) + suffix;\n        };\n\n    /**\n     * Provides get/set/isChanged/clear methods for work with cart data.\n     * Can be customized via mixin functionality.\n     */\n    return {\n        cartData: cartData,\n\n        /**\n         * Array of required address fields\n         */\n        requiredFields: ['countryId', 'region', 'regionId', 'postcode'],\n\n        /**\n         * Get data from customer data.\n         * Concatenate provided key with method name and call method if it exist or makes get by key.\n         *\n         * @param {String} key\n         * @return {*}\n         */\n        get: function (key) {\n            var methodName = getMethodName(key, '_get');\n\n            if (key === cacheKey) {\n                return getData();\n            }\n\n            if (this[methodName]) {\n                return this[methodName]();\n            }\n\n            return getData(key);\n        },\n\n        /**\n         * Set data to customer data.\n         * Concatenate provided key with method name and call method if it exist or makes set by key.\n         * @example _setCustomAddress method will be called, if it exists.\n         *  set('address', customAddressValue)\n         * @example Will set value by provided key.\n         *  set('rates', ratesToCompare)\n         *\n         * @param {String} key\n         * @param {*} value\n         */\n        set: function (key, value) {\n            var methodName = getMethodName(key, '_set'),\n                obj;\n\n            if (key === cacheKey) {\n                _.each(value, function (val, k) {\n                    this.set(k, val);\n                }, this);\n\n                return;\n            }\n\n            if (this[methodName]) {\n                this[methodName](value);\n            } else {\n                obj = getData();\n                obj[key] = value;\n                setData(obj);\n            }\n        },\n\n        /**\n         * Clear data in cache.\n         * Concatenate provided key with method name and call method if it exist or clear by key.\n         * @example _clearCustomAddress method will be called, if it exist.\n         *  clear('customAddress')\n         * @example Will clear data by provided key.\n         *  clear('rates')\n         *\n         * @param {String} key\n         */\n        clear: function (key) {\n            var methodName = getMethodName(key, '_clear');\n\n            if (key === cacheKey) {\n                setData(this.cartData);\n\n                return;\n            }\n\n            if (this[methodName]) {\n                this[methodName]();\n            } else {\n                this.set(key, null);\n            }\n        },\n\n        /**\n         * Check if provided data has difference with cached data.\n         * Concatenate provided key with method name and call method if it exist or makes strict equality.\n         * @example Will call existing _isAddressChanged.\n         *  isChanged('address', addressToCompare)\n         * @example Will get data by provided key and make strict equality with provided value.\n         *  isChanged('rates', ratesToCompare)\n         *\n         * @param {String} key\n         * @param {*} value\n         * @return {Boolean}\n         */\n        isChanged: function (key, value) {\n            var methodName = getMethodName(key, '_is', 'Changed');\n\n            if (this[methodName]) {\n                return this[methodName](value);\n            }\n\n            return this.get(key) !== value;\n        },\n\n        /**\n         * Compare cached address with provided.\n         * Custom method for check object equality.\n         *\n         * @param {Object} address\n         * @returns {Boolean}\n         */\n        _isAddressChanged: function (address) {\n            return JSON.stringify(_.pick(this.get('address'), this.requiredFields)) !==\n                JSON.stringify(_.pick(address, this.requiredFields));\n        },\n\n        /**\n         * Compare cached subtotal with provided.\n         * Custom method for check object equality.\n         *\n         * @param {float} subtotal\n         * @returns {Boolean}\n         */\n        _isSubtotalChanged: function (subtotal) {\n            var cached = parseFloat(this.get('totals').subtotal);\n\n            return subtotal !== cached;\n        }\n    };\n});\n","Magento_Checkout/js/model/cart/totals-processor/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Checkout/js/model/resource-url-manager',\n    'Magento_Checkout/js/model/quote',\n    'mage/storage',\n    'Magento_Checkout/js/model/totals',\n    'Magento_Checkout/js/model/error-processor',\n    'Magento_Checkout/js/model/cart/cache',\n    'Magento_Customer/js/customer-data'\n], function (_, resourceUrlManager, quote, storage, totalsService, errorProcessor, cartCache, customerData) {\n    'use strict';\n\n    /**\n     * Load data from server.\n     *\n     * @param {Object} address\n     */\n    var loadFromServer = function (address) {\n        var serviceUrl,\n            payload;\n\n        // Start loader for totals block\n        totalsService.isLoading(true);\n        serviceUrl = resourceUrlManager.getUrlForTotalsEstimationForNewAddress(quote);\n        payload = {\n            addressInformation: {\n                address: _.pick(address, cartCache.requiredFields)\n            }\n        };\n\n        if (quote.shippingMethod() && quote.shippingMethod()['method_code']) {\n            payload.addressInformation['shipping_method_code'] = quote.shippingMethod()['method_code'];\n            payload.addressInformation['shipping_carrier_code'] = quote.shippingMethod()['carrier_code'];\n        }\n\n        return storage.post(\n            serviceUrl, JSON.stringify(payload), false\n        ).done(function (result) {\n            var data = {\n                totals: result,\n                address: address,\n                cartVersion: customerData.get('cart')()['data_id'],\n                shippingMethodCode: null,\n                shippingCarrierCode: null\n            };\n\n            if (quote.shippingMethod() && quote.shippingMethod()['method_code']) {\n                data.shippingMethodCode = quote.shippingMethod()['method_code'];\n                data.shippingCarrierCode = quote.shippingMethod()['carrier_code'];\n            }\n\n            quote.setTotals(result);\n            cartCache.set('cart-data', data);\n        }).fail(function (response) {\n            errorProcessor.process(response);\n        }).always(function () {\n            // Stop loader for totals block\n            totalsService.isLoading(false);\n        });\n    };\n\n    return {\n        /**\n         * Array of required address fields.\n         * @property {Array.String} requiredFields\n         * @deprecated Use cart cache.\n         */\n        requiredFields: cartCache.requiredFields,\n\n        /**\n         * Get shipping rates for specified address.\n         * @param {Object} address\n         */\n        estimateTotals: function (address) {\n            return loadFromServer(address);\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-save-processor/payload-extender.js":"define([], function () {\n    'use strict';\n\n    return function (payload) {\n        payload.addressInformation['extension_attributes'] = {};\n\n        return payload;\n    };\n});\n","Magento_Checkout/js/model/shipping-save-processor/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/resource-url-manager',\n    'mage/storage',\n    'Magento_Checkout/js/model/payment-service',\n    'Magento_Checkout/js/model/payment/method-converter',\n    'Magento_Checkout/js/model/error-processor',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Checkout/js/action/select-billing-address',\n    'Magento_Checkout/js/model/shipping-save-processor/payload-extender'\n], function (\n    ko,\n    quote,\n    resourceUrlManager,\n    storage,\n    paymentService,\n    methodConverter,\n    errorProcessor,\n    fullScreenLoader,\n    selectBillingAddressAction,\n    payloadExtender\n) {\n    'use strict';\n\n    return {\n        /**\n         * @return {jQuery.Deferred}\n         */\n        saveShippingInformation: function () {\n            var payload;\n\n            if (!quote.billingAddress() && quote.shippingAddress().canUseForBilling()) {\n                selectBillingAddressAction(quote.shippingAddress());\n            }\n\n            payload = {\n                addressInformation: {\n                    'shipping_address': quote.shippingAddress(),\n                    'billing_address': quote.billingAddress(),\n                    'shipping_method_code': quote.shippingMethod()['method_code'],\n                    'shipping_carrier_code': quote.shippingMethod()['carrier_code']\n                }\n            };\n\n            payloadExtender(payload);\n\n            fullScreenLoader.startLoader();\n\n            return storage.post(\n                resourceUrlManager.getUrlForSetShippingInformation(quote),\n                JSON.stringify(payload)\n            ).done(\n                function (response) {\n                    quote.setTotals(response.totals);\n                    paymentService.setPaymentMethods(methodConverter(response['payment_methods']));\n                    fullScreenLoader.stopLoader();\n                }\n            ).fail(\n                function (response) {\n                    errorProcessor.process(response);\n                    fullScreenLoader.stopLoader();\n                }\n            );\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-address/form-popup-state.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko'\n], function (ko) {\n    'use strict';\n\n    return {\n        isVisible: ko.observable(false)\n    };\n});\n","Magento_Checkout/js/model/payment/method-list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko'\n], function (ko) {\n    'use strict';\n\n    return ko.observableArray([]);\n});\n","Magento_Checkout/js/model/payment/renderer-list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko'\n], function (ko) {\n    'use strict';\n\n    return ko.observableArray([]);\n});\n","Magento_Checkout/js/model/payment/additional-validators.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([], function () {\n    'use strict';\n\n    var validators = [];\n\n    return {\n        /**\n         * Register unique validator\n         *\n         * @param {*} validator\n         */\n        registerValidator: function (validator) {\n            validators.push(validator);\n        },\n\n        /**\n         * Returns array of registered validators\n         *\n         * @returns {Array}\n         */\n        getValidators: function () {\n            return validators;\n        },\n\n        /**\n         * Process validators\n         *\n         * @returns {Boolean}\n         */\n        validate: function (hideError) {\n            var validationResult = true;\n\n            hideError = hideError || false;\n\n            if (validators.length <= 0) {\n                return validationResult;\n            }\n\n            validators.forEach(function (item) {\n                if (item.validate(hideError) == false) { //eslint-disable-line eqeqeq\n                    validationResult = false;\n\n                    return false;\n                }\n            });\n\n            return validationResult;\n        }\n    };\n});\n","Magento_Checkout/js/model/payment/method-converter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    return function (methods) {\n        _.each(methods, function (method) {\n            if (method.hasOwnProperty('code')) {\n                method.method = method.code;\n                delete method.code;\n            }\n        });\n\n        return methods;\n    };\n});\n","Magento_Checkout/js/model/payment/method-group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n        'uiElement',\n        'mage/translate'\n], function (Element, $t) {\n    'use strict';\n\n    var DEFAULT_GROUP_ALIAS = 'default';\n\n    return Element.extend({\n        defaults: {\n            alias: DEFAULT_GROUP_ALIAS,\n            title: $t('Payment Method'),\n            sortOrder: 100,\n            displayArea: 'payment-methods-items-${ $.alias }'\n        },\n\n        /**\n         * Checks if group instance is default\n         *\n         * @returns {Boolean}\n         */\n        isDefault: function () {\n            return this.alias === DEFAULT_GROUP_ALIAS;\n        }\n    });\n});\n","Magento_Checkout/js/model/payment/place-order-hooks.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return {\n        requestModifiers: [],\n        afterRequestListeners: []\n    };\n});\n","Magento_Checkout/js/model/shipping-rate-processor/customer-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/model/resource-url-manager',\n    'Magento_Checkout/js/model/quote',\n    'mage/storage',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Checkout/js/model/shipping-rate-registry',\n    'Magento_Checkout/js/model/error-processor'\n], function (resourceUrlManager, quote, storage, shippingService, rateRegistry, errorProcessor) {\n    'use strict';\n\n    return {\n        /**\n         * @param {Object} address\n         */\n        getRates: function (address) {\n            var cache;\n\n            shippingService.isLoading(true);\n            cache = rateRegistry.get(address.getKey());\n\n            if (cache) {\n                shippingService.setShippingRates(cache);\n                shippingService.isLoading(false);\n            } else {\n                storage.post(\n                    resourceUrlManager.getUrlForEstimationShippingMethodsByAddressId(),\n                    JSON.stringify({\n                        addressId: address.customerAddressId\n                    }),\n                    false\n                ).done(function (result) {\n                    rateRegistry.set(address.getKey(), result);\n                    shippingService.setShippingRates(result);\n                }).fail(function (response) {\n                    shippingService.setShippingRates([]);\n                    errorProcessor.process(response);\n                }).always(function () {\n                    shippingService.isLoading(false);\n                }\n                );\n            }\n        }\n    };\n});\n","Magento_Checkout/js/model/shipping-rate-processor/new-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Checkout/js/model/resource-url-manager',\n    'Magento_Checkout/js/model/quote',\n    'mage/storage',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Checkout/js/model/shipping-rate-registry',\n    'Magento_Checkout/js/model/error-processor'\n], function (resourceUrlManager, quote, storage, shippingService, rateRegistry, errorProcessor) {\n    'use strict';\n\n    return {\n        /**\n         * Get shipping rates for specified address.\n         * @param {Object} address\n         */\n        getRates: function (address) {\n            var cache, serviceUrl, payload;\n\n            shippingService.isLoading(true);\n            cache = rateRegistry.get(address.getCacheKey());\n            serviceUrl = resourceUrlManager.getUrlForEstimationShippingMethodsForNewAddress(quote);\n            payload = JSON.stringify({\n                    address: {\n                        'street': address.street,\n                        'city': address.city,\n                        'region_id': address.regionId,\n                        'region': address.region,\n                        'country_id': address.countryId,\n                        'postcode': address.postcode,\n                        'email': address.email,\n                        'customer_id': address.customerId,\n                        'firstname': address.firstname,\n                        'lastname': address.lastname,\n                        'middlename': address.middlename,\n                        'prefix': address.prefix,\n                        'suffix': address.suffix,\n                        'vat_id': address.vatId,\n                        'company': address.company,\n                        'telephone': address.telephone,\n                        'fax': address.fax,\n                        'custom_attributes': address.customAttributes,\n                        'save_in_address_book': address.saveInAddressBook\n                    }\n                }\n            );\n\n            if (cache) {\n                shippingService.setShippingRates(cache);\n                shippingService.isLoading(false);\n            } else {\n                storage.post(\n                    serviceUrl, payload, false\n                ).done(function (result) {\n                    rateRegistry.set(address.getCacheKey(), result);\n                    shippingService.setShippingRates(result);\n                }).fail(function (response) {\n                    shippingService.setShippingRates([]);\n                    errorProcessor.process(response);\n                }).always(function () {\n                    shippingService.isLoading(false);\n                });\n            }\n        }\n    };\n});\n","Magento_Checkout/js/view/billing-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'Magento_Ui/js/form/form',\n    'Magento_Customer/js/model/customer',\n    'Magento_Customer/js/model/address-list',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/action/create-billing-address',\n    'Magento_Checkout/js/action/select-billing-address',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'Magento_Customer/js/customer-data',\n    'Magento_Checkout/js/action/set-billing-address',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate',\n    'Magento_Checkout/js/model/billing-address-postcode-validator',\n    'Magento_Checkout/js/model/address-converter'\n],\nfunction (\n    ko,\n    _,\n    Component,\n    customer,\n    addressList,\n    quote,\n    createBillingAddress,\n    selectBillingAddress,\n    checkoutData,\n    checkoutDataResolver,\n    customerData,\n    setBillingAddressAction,\n    globalMessageList,\n    $t,\n    billingAddressPostcodeValidator,\n    addressConverter\n) {\n    'use strict';\n\n    var lastSelectedBillingAddress = null,\n        addressUpdated = false,\n        addressEdited = false,\n        countryData = customerData.get('directory-data'),\n        addressOptions = addressList().filter(function (address) {\n            return address.getType() === 'customer-address';\n        });\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/billing-address',\n            actionsTemplate: 'Magento_Checkout/billing-address/actions',\n            formTemplate: 'Magento_Checkout/billing-address/form',\n            detailsTemplate: 'Magento_Checkout/billing-address/details',\n            links: {\n                isAddressFormVisible: '${$.billingAddressListProvider}:isNewAddressSelected'\n            }\n        },\n        currentBillingAddress: quote.billingAddress,\n        customerHasAddresses: addressOptions.length > 0,\n\n        /**\n         * Init component\n         */\n        initialize: function () {\n            this._super();\n            quote.paymentMethod.subscribe(function () {\n                checkoutDataResolver.resolveBillingAddress();\n            }, this);\n            billingAddressPostcodeValidator.initFields(this.get('name') + '.form-fields');\n        },\n\n        /**\n         * @return {exports.initObservable}\n         */\n        initObservable: function () {\n            this._super()\n                .observe({\n                    selectedAddress: null,\n                    isAddressDetailsVisible: quote.billingAddress() != null,\n                    isAddressFormVisible: !customer.isLoggedIn() || !addressOptions.length,\n                    isAddressSameAsShipping: false,\n                    saveInAddressBook: 1\n                });\n\n            quote.billingAddress.subscribe(function (newAddress) {\n                if (quote.isVirtual()) {\n                    this.isAddressSameAsShipping(false);\n                } else {\n                    this.isAddressSameAsShipping(\n                        newAddress != null &&\n                        newAddress.getCacheKey() == quote.shippingAddress().getCacheKey() //eslint-disable-line eqeqeq\n                    );\n                }\n\n                if (newAddress != null && newAddress.saveInAddressBook !== undefined) {\n                    this.saveInAddressBook(newAddress.saveInAddressBook);\n                } else {\n                    this.saveInAddressBook(1);\n                }\n                this.isAddressDetailsVisible(true);\n            }, this);\n\n            return this;\n        },\n\n        canUseShippingAddress: ko.computed(function () {\n            return !quote.isVirtual() && quote.shippingAddress() && quote.shippingAddress().canUseForBilling();\n        }),\n\n        /**\n         * @param {Object} address\n         * @return {*}\n         */\n        addressOptionsText: function (address) {\n            return address.getAddressInline();\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        useShippingAddress: function () {\n            if (this.isAddressSameAsShipping()) {\n                selectBillingAddress(quote.shippingAddress());\n                this.updateAddresses(true);\n                this.isAddressDetailsVisible(true);\n            } else {\n                lastSelectedBillingAddress = quote.billingAddress();\n                quote.billingAddress(null);\n                this.isAddressDetailsVisible(false);\n            }\n            checkoutData.setSelectedBillingAddress(null);\n\n            return true;\n        },\n\n        /**\n         * Update address action\n         */\n        updateAddress: function () {\n            var addressData, newBillingAddress;\n\n            addressUpdated = true;\n\n            if (this.selectedAddress() && !this.isAddressFormVisible()) {\n                selectBillingAddress(this.selectedAddress());\n                checkoutData.setSelectedBillingAddress(this.selectedAddress().getKey());\n            } else {\n                this.source.set('params.invalid', false);\n                this.source.trigger(this.dataScopePrefix + '.data.validate');\n\n                if (this.source.get(this.dataScopePrefix + '.custom_attributes')) {\n                    this.source.trigger(this.dataScopePrefix + '.custom_attributes.data.validate');\n                }\n\n                if (!this.source.get('params.invalid')) {\n                    addressData = this.source.get(this.dataScopePrefix);\n\n                    if (customer.isLoggedIn() && !this.customerHasAddresses) { //eslint-disable-line max-depth\n                        this.saveInAddressBook(1);\n                    }\n                    addressData['save_in_address_book'] = this.saveInAddressBook() ? 1 : 0;\n                    newBillingAddress = createBillingAddress(addressData);\n                    // New address must be selected as a billing address\n                    selectBillingAddress(newBillingAddress);\n                    checkoutData.setSelectedBillingAddress(newBillingAddress.getKey());\n                    checkoutData.setNewCustomerBillingAddress(addressData);\n                }\n            }\n            this.updateAddresses(true);\n        },\n\n        /**\n         * Edit address action\n         */\n        editAddress: function () {\n            addressUpdated = false;\n            addressEdited = true;\n            lastSelectedBillingAddress = quote.billingAddress();\n            quote.billingAddress(null);\n            this.isAddressDetailsVisible(false);\n        },\n\n        /**\n         * Cancel address edit action\n         */\n        cancelAddressEdit: function () {\n            addressUpdated = true;\n            this.restoreBillingAddress();\n\n            if (quote.billingAddress()) {\n                // restore 'Same As Shipping' checkbox state\n                this.isAddressSameAsShipping(\n                    quote.billingAddress() != null &&\n                        quote.billingAddress().getCacheKey() == quote.shippingAddress().getCacheKey() && //eslint-disable-line\n                        !quote.isVirtual()\n                );\n                this.isAddressDetailsVisible(true);\n            }\n        },\n\n        /**\n         * Manage cancel button visibility\n         */\n        canUseCancelBillingAddress: ko.computed(function () {\n            return quote.billingAddress() || lastSelectedBillingAddress;\n        }),\n\n        /**\n         * Check if Billing Address Changes should be canceled\n         */\n        needCancelBillingAddressChanges: function () {\n            if (addressEdited && !addressUpdated) {\n                this.cancelAddressEdit();\n            }\n        },\n\n        /**\n         * Restore billing address\n         */\n        restoreBillingAddress: function () {\n            var lastBillingAddress;\n\n            if (lastSelectedBillingAddress != null) {\n                selectBillingAddress(lastSelectedBillingAddress);\n                lastBillingAddress = addressConverter.quoteAddressToFormAddressData(lastSelectedBillingAddress);\n\n                checkoutData.setNewCustomerBillingAddress(lastBillingAddress);\n            }\n        },\n\n        /**\n         * @param {Number} countryId\n         * @return {*}\n         */\n        getCountryName: function (countryId) {\n            return countryData()[countryId] != undefined ? countryData()[countryId].name : ''; //eslint-disable-line\n        },\n\n        /**\n         * Trigger action to update shipping and billing addresses\n         *\n         * @param {Boolean} force\n         */\n        updateAddresses: function (force) {\n            force = !(typeof force === 'undefined' || force !== true);\n\n            if (force\n                || window.checkoutConfig.reloadOnBillingAddress\n                || !window.checkoutConfig.displayBillingOnPaymentMethod) {\n                setBillingAddressAction(globalMessageList);\n            }\n        },\n\n        /**\n         * Get code\n         * @param {Object} parent\n         * @returns {String}\n         */\n        getCode: function (parent) {\n            return _.isFunction(parent.getCode) ? parent.getCode() : 'shared';\n        },\n\n        /**\n         * Get customer attribute label\n         *\n         * @param {*} attribute\n         * @returns {*}\n         */\n        getCustomAttributeLabel: function (attribute) {\n            var label;\n\n            if (typeof attribute === 'string') {\n                return attribute;\n            }\n\n            if (attribute.label) {\n                return attribute.label;\n            }\n\n            if (_.isArray(attribute.value)) {\n                label = _.map(attribute.value, function (value) {\n                    return this.getCustomAttributeOptionLabel(attribute['attribute_code'], value) || value;\n                }, this).join(', ');\n            } else if (typeof attribute.value === 'object') {\n                label = _.map(Object.values(attribute.value)).join(', ');\n            } else {\n                label = this.getCustomAttributeOptionLabel(attribute['attribute_code'], attribute.value);\n            }\n\n            return label || attribute.value;\n        },\n\n        /**\n         * Get option label for given attribute code and option ID\n         *\n         * @param {String} attributeCode\n         * @param {String} value\n         * @returns {String|null}\n         */\n        getCustomAttributeOptionLabel: function (attributeCode, value) {\n            var option,\n                label,\n                options = this.source.get('customAttributes') || {};\n\n            if (options[attributeCode]) {\n                option = _.findWhere(options[attributeCode], {\n                    value: value\n                });\n\n                if (option) {\n                    label = option.label;\n                }\n            } else if (value.file !== null) {\n                label = value.file;\n            }\n\n            return label;\n        }\n    });\n});\n","Magento_Checkout/js/view/authentication-messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/view/messages',\n    'Magento_Checkout/js/model/authentication-messages'\n], function (Component, messageContainer) {\n    'use strict';\n\n    return Component.extend({\n        /** @inheritdoc */\n        initialize: function (config) {\n            return this._super(config, messageContainer);\n        }\n    });\n});\n","Magento_Checkout/js/view/cart-item-renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * Prepare the product name value to be rendered as HTML\n         *\n         * @param {String} productName\n         * @return {String}\n         */\n        getProductNameUnsanitizedHtml: function (productName) {\n            // product name has already escaped on backend\n            return productName;\n        },\n\n        /**\n         * Prepare the given option value to be rendered as HTML\n         *\n         * @param {String} optionValue\n         * @return {String}\n         */\n        getOptionValueUnsanitizedHtml: function (optionValue) {\n            // option value has already escaped on backend\n            return optionValue;\n        }\n    });\n});\n","Magento_Checkout/js/view/summary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/totals'\n], function (Component, totals) {\n    'use strict';\n\n    return Component.extend({\n        isLoading: totals.isLoading\n    });\n});\n","Magento_Checkout/js/view/estimation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Catalog/js/price-utils',\n    'Magento_Checkout/js/model/totals',\n    'Magento_Checkout/js/model/sidebar'\n], function (Component, quote, priceUtils, totals, sidebarModel) {\n    'use strict';\n\n    return Component.extend({\n        isLoading: totals.isLoading,\n\n        /**\n         * @return {Number}\n         */\n        getQuantity: function () {\n            if (totals.totals()) {\n                return parseFloat(totals.totals()['items_qty']);\n            }\n\n            return 0;\n        },\n\n        /**\n         * @return {Number}\n         */\n        getPureValue: function () {\n            if (totals.totals()) {\n                return parseFloat(totals.getSegment('grand_total').value);\n            }\n\n            return 0;\n        },\n\n        /**\n         * Show sidebar.\n         */\n        showSidebar: function () {\n            sidebarModel.show();\n        },\n\n        /**\n         * @param {*} price\n         * @return {*|String}\n         */\n        getFormattedPrice: function (price) {\n            return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getValue: function () {\n            return this.getFormattedPrice(this.getPureValue());\n        }\n    });\n});\n","Magento_Checkout/js/view/progress-bar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'ko',\n    'uiComponent',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/view/billing-address'\n], function ($, _, ko, Component, stepNavigator, billingAddress) {\n    'use strict';\n\n    var steps = stepNavigator.steps;\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/progress-bar',\n            visible: true\n        },\n        steps: steps,\n\n        /** @inheritdoc */\n        initialize: function () {\n            var stepsValue;\n\n            this._super();\n            window.addEventListener('hashchange', _.bind(stepNavigator.handleHash, stepNavigator));\n\n            if (!window.location.hash) {\n                stepsValue = stepNavigator.steps();\n\n                if (stepsValue.length) {\n                    stepNavigator.setHash(stepsValue.sort(stepNavigator.sortItems)[0].code);\n                }\n            }\n\n            stepNavigator.handleHash();\n        },\n\n        /**\n         * @param {*} itemOne\n         * @param {*} itemTwo\n         * @return {*|Number}\n         */\n        sortItems: function (itemOne, itemTwo) {\n            return stepNavigator.sortItems(itemOne, itemTwo);\n        },\n\n        /**\n         * @param {Object} step\n         */\n        navigateTo: function (step) {\n            if (step.code === 'shipping') {\n                billingAddress().needCancelBillingAddressChanges();\n            }\n            stepNavigator.navigateTo(step.code);\n        },\n\n        /**\n         * @param {Object} item\n         * @return {*|Boolean}\n         */\n        isProcessed: function (item) {\n            return stepNavigator.isProcessed(item.code);\n        }\n    });\n});\n","Magento_Checkout/js/view/minicart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Customer/js/customer-data',\n    'jquery',\n    'ko',\n    'underscore',\n    'sidebar',\n    'mage/translate',\n    'mage/dropdown'\n], function (Component, customerData, $, ko, _) {\n    'use strict';\n\n    var sidebarInitialized = false,\n        addToCartCalls = 0,\n        miniCart;\n\n    miniCart = $('[data-block=\\'minicart\\']');\n\n    /**\n     * @return {Boolean}\n     */\n    function initSidebar() {\n        if (miniCart.data('mageSidebar')) {\n            miniCart.sidebar('update');\n        }\n\n        if (!$('[data-role=product-item]').length) {\n            return false;\n        }\n        miniCart.trigger('contentUpdated');\n\n        if (sidebarInitialized) {\n            return false;\n        }\n        sidebarInitialized = true;\n        miniCart.sidebar({\n            'targetElement': 'div.block.block-minicart',\n            'url': {\n                'checkout': window.checkout.checkoutUrl,\n                'update': window.checkout.updateItemQtyUrl,\n                'remove': window.checkout.removeItemUrl,\n                'loginUrl': window.checkout.customerLoginUrl,\n                'isRedirectRequired': window.checkout.isRedirectRequired\n            },\n            'button': {\n                'checkout': '#top-cart-btn-checkout',\n                'remove': '#mini-cart a.action.delete',\n                'close': '#btn-minicart-close'\n            },\n            'showcart': {\n                'parent': 'span.counter',\n                'qty': 'span.counter-number',\n                'label': 'span.counter-label'\n            },\n            'minicart': {\n                'list': '#mini-cart',\n                'content': '#minicart-content-wrapper',\n                'qty': 'div.items-total',\n                'subtotal': 'div.subtotal span.price',\n                'maxItemsVisible': window.checkout.minicartMaxItemsVisible\n            },\n            'item': {\n                'qty': ':input.cart-item-qty',\n                'button': ':button.update-cart-item'\n            },\n            'confirmMessage': $.mage.__('Are you sure you would like to remove this item from the shopping cart?')\n        });\n    }\n\n    miniCart.on('dropdowndialogopen', function () {\n        initSidebar();\n    });\n\n    return Component.extend({\n        shoppingCartUrl: window.checkout.shoppingCartUrl,\n        maxItemsToDisplay: window.checkout.maxItemsToDisplay,\n        cart: {},\n\n        // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n        /**\n         * @override\n         */\n        initialize: function () {\n            var self = this,\n                cartData = customerData.get('cart');\n\n            this.update(cartData());\n            cartData.subscribe(function (updatedCart) {\n                addToCartCalls--;\n                this.isLoading(addToCartCalls > 0);\n                sidebarInitialized = false;\n                this.update(updatedCart);\n                initSidebar();\n            }, this);\n            $('[data-block=\"minicart\"]').on('contentLoading', function () {\n                addToCartCalls++;\n                self.isLoading(true);\n            });\n\n            if (\n                cartData().website_id !== window.checkout.websiteId && cartData().website_id !== undefined ||\n                cartData().storeId !== window.checkout.storeId && cartData().storeId !== undefined\n            ) {\n                customerData.reload(['cart'], false);\n            }\n\n            return this._super();\n        },\n        //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n        isLoading: ko.observable(false),\n        initSidebar: initSidebar,\n\n        /**\n         * Close mini shopping cart.\n         */\n        closeMinicart: function () {\n            $('[data-block=\"minicart\"]').find('[data-role=\"dropdownDialog\"]').dropdownDialog('close');\n        },\n\n        /**\n         * @param {String} productType\n         * @return {*|String}\n         */\n        getItemRenderer: function (productType) {\n            return this.itemRenderer[productType] || 'defaultRenderer';\n        },\n\n        /**\n         * Update mini shopping cart content.\n         *\n         * @param {Object} updatedCart\n         * @returns void\n         */\n        update: function (updatedCart) {\n            _.each(updatedCart, function (value, key) {\n                if (!this.cart.hasOwnProperty(key)) {\n                    this.cart[key] = ko.observable();\n                }\n                this.cart[key](value);\n            }, this);\n        },\n\n        /**\n         * Get cart param by name.\n         *\n         * @param {String} name\n         * @returns {*}\n         */\n        getCartParamUnsanitizedHtml: function (name) {\n            if (!_.isUndefined(name)) {\n                if (!this.cart.hasOwnProperty(name)) {\n                    this.cart[name] = ko.observable();\n                }\n            }\n\n            return this.cart[name]();\n        },\n\n        /**\n         * @deprecated please use getCartParamUnsanitizedHtml.\n         * @param {String} name\n         * @returns {*}\n         */\n        getCartParam: function (name) {\n            return this.getCartParamUnsanitizedHtml(name);\n        },\n\n        /**\n         * Returns array of cart items, limited by 'maxItemsToDisplay' setting\n         * @returns []\n         */\n        getCartItems: function () {\n            var items = this.getCartParamUnsanitizedHtml('items') || [];\n\n            items = items.slice(parseInt(-this.maxItemsToDisplay, 10));\n\n            return items;\n        },\n\n        /**\n         * Returns count of cart line items\n         * @returns {Number}\n         */\n        getCartLineItemsCount: function () {\n            var items = this.getCartParamUnsanitizedHtml('items') || [];\n\n            return parseInt(items.length, 10);\n        }\n    });\n});\n","Magento_Checkout/js/view/sidebar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'ko',\n    'jquery',\n    'Magento_Checkout/js/model/sidebar'\n], function (Component, ko, $, sidebarModel) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @param {HTMLElement} element\n         */\n        setModalElement: function (element) {\n            sidebarModel.setPopup($(element));\n        }\n    });\n});\n","Magento_Checkout/js/view/authentication.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/form/form',\n    'Magento_Customer/js/action/login',\n    'Magento_Customer/js/model/customer',\n    'mage/validation',\n    'Magento_Checkout/js/model/authentication-messages',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, Component, loginAction, customer, validation, messageContainer, fullScreenLoader) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig;\n\n    return Component.extend({\n        isGuestCheckoutAllowed: checkoutConfig.isGuestCheckoutAllowed,\n        isCustomerLoginRequired: checkoutConfig.isCustomerLoginRequired,\n        registerUrl: checkoutConfig.registerUrl,\n        forgotPasswordUrl: checkoutConfig.forgotPasswordUrl,\n        autocomplete: checkoutConfig.autocomplete,\n        defaults: {\n            template: 'Magento_Checkout/authentication'\n        },\n\n        /**\n         * Is login form enabled for current customer.\n         *\n         * @return {Boolean}\n         */\n        isActive: function () {\n            return !customer.isLoggedIn();\n        },\n\n        /**\n         * Provide login action.\n         *\n         * @param {HTMLElement} loginForm\n         */\n        login: function (loginForm) {\n            var loginData = {},\n                formDataArray = $(loginForm).serializeArray();\n\n            formDataArray.forEach(function (entry) {\n                loginData[entry.name] = entry.value;\n            });\n\n            if ($(loginForm).validation() &&\n                $(loginForm).validation('isValid')\n            ) {\n                fullScreenLoader.startLoader();\n                loginAction(loginData, checkoutConfig.checkoutUrl, undefined, messageContainer).always(function () {\n                    fullScreenLoader.stopLoader();\n                });\n            }\n        }\n    });\n});\n","Magento_Checkout/js/view/registration.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiComponent',\n    'Magento_Ui/js/model/messageList'\n], function ($, Component, messageList) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/registration',\n            accountCreated: false,\n            creationStarted: false,\n            isFormVisible: true\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initObservable: function () {\n            this._super()\n                .observe('accountCreated')\n                .observe('isFormVisible')\n                .observe('creationStarted');\n\n            return this;\n        },\n\n        /**\n         * @return {*}\n         */\n        getEmailAddress: function () {\n            return this.email;\n        },\n\n        /**\n         * @return String\n         */\n        getUrl: function () {\n            return this.registrationUrl;\n        },\n\n        /**\n         * Create new user account.\n         *\n         * @deprecated\n         */\n        createAccount: function () {\n            this.creationStarted(true);\n            $.post(\n                this.registrationUrl\n            ).done(\n                function (response) {\n\n                    if (response.errors == false) { //eslint-disable-line eqeqeq\n                        this.accountCreated(true);\n                    } else {\n                        messageList.addErrorMessage(response);\n                    }\n                    this.isFormVisible(false);\n                }.bind(this)\n            ).fail(\n                function (response) {\n                    this.accountCreated(false);\n                    this.isFormVisible(false);\n                    messageList.addErrorMessage(response);\n                }.bind(this)\n            );\n        }\n    });\n});\n","Magento_Checkout/js/view/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Ui/js/form/form',\n    'ko',\n    'Magento_Customer/js/model/customer',\n    'Magento_Customer/js/model/address-list',\n    'Magento_Checkout/js/model/address-converter',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/action/create-shipping-address',\n    'Magento_Checkout/js/action/select-shipping-address',\n    'Magento_Checkout/js/model/shipping-rates-validator',\n    'Magento_Checkout/js/model/shipping-address/form-popup-state',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Checkout/js/action/select-shipping-method',\n    'Magento_Checkout/js/model/shipping-rate-registry',\n    'Magento_Checkout/js/action/set-shipping-information',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Ui/js/modal/modal',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'Magento_Checkout/js/checkout-data',\n    'uiRegistry',\n    'mage/translate',\n    'Magento_Checkout/js/model/shipping-rate-service'\n], function (\n    $,\n    _,\n    Component,\n    ko,\n    customer,\n    addressList,\n    addressConverter,\n    quote,\n    createShippingAddress,\n    selectShippingAddress,\n    shippingRatesValidator,\n    formPopUpState,\n    shippingService,\n    selectShippingMethodAction,\n    rateRegistry,\n    setShippingInformationAction,\n    stepNavigator,\n    modal,\n    checkoutDataResolver,\n    checkoutData,\n    registry,\n    $t\n) {\n    'use strict';\n\n    var popUp = null;\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/shipping',\n            shippingFormTemplate: 'Magento_Checkout/shipping-address/form',\n            shippingMethodListTemplate: 'Magento_Checkout/shipping-address/shipping-method-list',\n            shippingMethodItemTemplate: 'Magento_Checkout/shipping-address/shipping-method-item',\n            imports: {\n                countryOptions: '${ $.parentName }.shippingAddress.shipping-address-fieldset.country_id:indexedOptions'\n            }\n        },\n        visible: ko.observable(!quote.isVirtual()),\n        errorValidationMessage: ko.observable(false),\n        isCustomerLoggedIn: customer.isLoggedIn,\n        isFormPopUpVisible: formPopUpState.isVisible,\n        isFormInline: addressList().length === 0,\n        isNewAddressAdded: ko.observable(false),\n        saveInAddressBook: 1,\n        quoteIsVirtual: quote.isVirtual(),\n\n        /**\n         * @return {exports}\n         */\n        initialize: function () {\n            var self = this,\n                hasNewAddress,\n                fieldsetName = 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset';\n\n            this._super();\n\n            if (!quote.isVirtual()) {\n                stepNavigator.registerStep(\n                    'shipping',\n                    '',\n                    $t('Shipping'),\n                    this.visible, _.bind(this.navigate, this),\n                    this.sortOrder\n                );\n            }\n            checkoutDataResolver.resolveShippingAddress();\n\n            hasNewAddress = addressList.some(function (address) {\n                return address.getType() == 'new-customer-address'; //eslint-disable-line eqeqeq\n            });\n\n            this.isNewAddressAdded(hasNewAddress);\n\n            this.isFormPopUpVisible.subscribe(function (value) {\n                if (value) {\n                    self.getPopUp().openModal();\n                }\n            });\n\n            quote.shippingMethod.subscribe(function () {\n                self.errorValidationMessage(false);\n            });\n\n            registry.async('checkoutProvider')(function (checkoutProvider) {\n                var shippingAddressData = checkoutData.getShippingAddressFromData();\n\n                if (shippingAddressData) {\n                    checkoutProvider.set(\n                        'shippingAddress',\n                        $.extend(true, {}, checkoutProvider.get('shippingAddress'), shippingAddressData)\n                    );\n                }\n                checkoutProvider.on('shippingAddress', function (shippingAddrsData, changes) {\n                    var isStreetAddressDeleted, isStreetAddressNotEmpty;\n\n                    /**\n                     * In last modifying operation street address was deleted.\n                     * @return {Boolean}\n                     */\n                    isStreetAddressDeleted = function () {\n                        var change;\n\n                        if (!changes || changes.length === 0) {\n                            return false;\n                        }\n\n                        change = changes.pop();\n\n                        if (_.isUndefined(change.value) || _.isUndefined(change.oldValue)) {\n                            return false;\n                        }\n\n                        if (!change.path.startsWith('shippingAddress.street')) {\n                            return false;\n                        }\n\n                        return change.value.length === 0 && change.oldValue.length > 0;\n                    };\n\n                    isStreetAddressNotEmpty = shippingAddrsData.street && !_.isEmpty(shippingAddrsData.street[0]);\n\n                    if (isStreetAddressNotEmpty || isStreetAddressDeleted()) {\n                        checkoutData.setShippingAddressFromData(shippingAddrsData);\n                    }\n                });\n                shippingRatesValidator.initFields(fieldsetName);\n            });\n\n            return this;\n        },\n\n        /**\n         * Navigator change hash handler.\n         *\n         * @param {Object} step - navigation step\n         */\n        navigate: function (step) {\n            step && step.isVisible(true);\n        },\n\n        /**\n         * @return {*}\n         */\n        getPopUp: function () {\n            var self = this,\n                buttons;\n\n            if (!popUp) {\n                buttons = this.popUpForm.options.buttons;\n                this.popUpForm.options.buttons = [\n                    {\n                        text: buttons.save.text ? buttons.save.text : $t('Save Address'),\n                        class: buttons.save.class ? buttons.save.class : 'action primary action-save-address',\n                        click: self.saveNewAddress.bind(self)\n                    },\n                    {\n                        text: buttons.cancel.text ? buttons.cancel.text : $t('Cancel'),\n                        class: buttons.cancel.class ? buttons.cancel.class : 'action secondary action-hide-popup',\n\n                        /** @inheritdoc */\n                        click: this.onClosePopUp.bind(this)\n                    }\n                ];\n\n                /** @inheritdoc */\n                this.popUpForm.options.closed = function () {\n                    self.isFormPopUpVisible(false);\n                };\n\n                this.popUpForm.options.modalCloseBtnHandler = this.onClosePopUp.bind(this);\n                this.popUpForm.options.keyEventHandlers = {\n                    escapeKey: this.onClosePopUp.bind(this)\n                };\n\n                /** @inheritdoc */\n                this.popUpForm.options.opened = function () {\n                    // Store temporary address for revert action in case when user click cancel action\n                    self.temporaryAddress = $.extend(true, {}, checkoutData.getShippingAddressFromData());\n                };\n                popUp = modal(this.popUpForm.options, $(this.popUpForm.element));\n            }\n\n            return popUp;\n        },\n\n        /**\n         * Revert address and close modal.\n         */\n        onClosePopUp: function () {\n            checkoutData.setShippingAddressFromData($.extend(true, {}, this.temporaryAddress));\n            this.getPopUp().closeModal();\n        },\n\n        /**\n         * Show address form popup\n         */\n        showFormPopUp: function () {\n            this.isFormPopUpVisible(true);\n        },\n\n        /**\n         * Save new shipping address\n         */\n        saveNewAddress: function () {\n            var addressData,\n                newShippingAddress;\n\n            this.source.set('params.invalid', false);\n            this.triggerShippingDataValidateEvent();\n\n            if (!this.source.get('params.invalid')) {\n                addressData = this.source.get('shippingAddress');\n                // if user clicked the checkbox, its value is true or false. Need to convert.\n                addressData['save_in_address_book'] = this.saveInAddressBook ? 1 : 0;\n\n                // New address must be selected as a shipping address\n                newShippingAddress = createShippingAddress(addressData);\n                selectShippingAddress(newShippingAddress);\n                checkoutData.setSelectedShippingAddress(newShippingAddress.getKey());\n                checkoutData.setNewCustomerShippingAddress($.extend(true, {}, addressData));\n                this.getPopUp().closeModal();\n                this.isNewAddressAdded(true);\n            }\n        },\n\n        /**\n         * Shipping Method View\n         */\n        rates: shippingService.getShippingRates(),\n        isLoading: shippingService.isLoading,\n        isSelected: ko.computed(function () {\n            return quote.shippingMethod() ?\n                quote.shippingMethod()['carrier_code'] + '_' + quote.shippingMethod()['method_code'] :\n                null;\n        }),\n\n        /**\n         * @param {Object} shippingMethod\n         * @return {Boolean}\n         */\n        selectShippingMethod: function (shippingMethod) {\n            selectShippingMethodAction(shippingMethod);\n            checkoutData.setSelectedShippingRate(shippingMethod['carrier_code'] + '_' + shippingMethod['method_code']);\n\n            return true;\n        },\n\n        /**\n         * Set shipping information handler\n         */\n        setShippingInformation: function () {\n            if (this.validateShippingInformation()) {\n                quote.billingAddress(null);\n                checkoutDataResolver.resolveBillingAddress();\n                registry.async('checkoutProvider')(function (checkoutProvider) {\n                    var shippingAddressData = checkoutData.getShippingAddressFromData();\n\n                    if (shippingAddressData) {\n                        checkoutProvider.set(\n                            'shippingAddress',\n                            $.extend(true, {}, checkoutProvider.get('shippingAddress'), shippingAddressData)\n                        );\n                    }\n                });\n                setShippingInformationAction().done(\n                    function () {\n                        stepNavigator.next();\n                    }\n                );\n            }\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        validateShippingInformation: function () {\n            var shippingAddress,\n                addressData,\n                loginFormSelector = 'form[data-role=email-with-possible-login]',\n                emailValidationResult = customer.isLoggedIn(),\n                field,\n                option = _.isObject(this.countryOptions) && this.countryOptions[quote.shippingAddress().countryId],\n                messageContainer = registry.get('checkout.errors').messageContainer;\n\n            if (!quote.shippingMethod()) {\n                this.errorValidationMessage(\n                    $t('The shipping method is missing. Select the shipping method and try again.')\n                );\n\n                return false;\n            }\n\n            if (!customer.isLoggedIn()) {\n                $(loginFormSelector).validation();\n                emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());\n            }\n\n            if (this.isFormInline) {\n                this.source.set('params.invalid', false);\n                this.triggerShippingDataValidateEvent();\n\n                if (!quote.shippingMethod()['method_code']) {\n                    this.errorValidationMessage(\n                        $t('The shipping method is missing. Select the shipping method and try again.')\n                    );\n                }\n\n                if (emailValidationResult &&\n                    this.source.get('params.invalid') ||\n                    !quote.shippingMethod()['method_code'] ||\n                    !quote.shippingMethod()['carrier_code']\n                ) {\n                    this.focusInvalid();\n\n                    return false;\n                }\n\n                shippingAddress = quote.shippingAddress();\n                addressData = addressConverter.formAddressDataToQuoteAddress(\n                    this.source.get('shippingAddress')\n                );\n\n                //Copy form data to quote shipping address object\n                for (field in addressData) {\n                    if (addressData.hasOwnProperty(field) &&  //eslint-disable-line max-depth\n                        shippingAddress.hasOwnProperty(field) &&\n                        typeof addressData[field] != 'function' &&\n                        _.isEqual(shippingAddress[field], addressData[field])\n                    ) {\n                        shippingAddress[field] = addressData[field];\n                    } else if (typeof addressData[field] != 'function' &&\n                        !_.isEqual(shippingAddress[field], addressData[field])) {\n                        shippingAddress = addressData;\n                        break;\n                    }\n                }\n\n                if (customer.isLoggedIn()) {\n                    shippingAddress['save_in_address_book'] = 1;\n                }\n                selectShippingAddress(shippingAddress);\n            } else if (customer.isLoggedIn() &&\n                option &&\n                option['is_region_required'] &&\n                !quote.shippingAddress().region\n            ) {\n                messageContainer.addErrorMessage({\n                    message: $t('Please specify a regionId in shipping address.')\n                });\n\n                return false;\n            }\n\n            if (!emailValidationResult) {\n                $(loginFormSelector + ' input[name=username]').trigger('focus');\n\n                return false;\n            }\n\n            return true;\n        },\n\n        /**\n         * Trigger Shipping data Validate Event.\n         */\n        triggerShippingDataValidateEvent: function () {\n            this.source.trigger('shippingAddress.data.validate');\n\n            if (this.source.get('shippingAddress.custom_attributes')) {\n                this.source.trigger('shippingAddress.custom_attributes.data.validate');\n            }\n        }\n    });\n});\n","Magento_Checkout/js/view/payment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'ko',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/model/payment-service',\n    'Magento_Checkout/js/model/payment/method-converter',\n    'Magento_Checkout/js/action/get-payment-information',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'mage/translate'\n], function (\n    $,\n    _,\n    Component,\n    ko,\n    quote,\n    stepNavigator,\n    paymentService,\n    methodConverter,\n    getPaymentInformation,\n    checkoutDataResolver,\n    $t\n) {\n    'use strict';\n\n    /** Set payment methods to collection */\n    paymentService.setPaymentMethods(methodConverter(window.checkoutConfig.paymentMethods));\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/payment',\n            activeMethod: ''\n        },\n        isVisible: ko.observable(quote.isVirtual()),\n        quoteIsVirtual: quote.isVirtual(),\n        isPaymentMethodsAvailable: ko.computed(function () {\n            return paymentService.getAvailablePaymentMethods().length > 0;\n        }),\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            checkoutDataResolver.resolvePaymentMethod();\n            stepNavigator.registerStep(\n                'payment',\n                null,\n                $t('Review & Payments'),\n                this.isVisible,\n                _.bind(this.navigate, this),\n                this.sortOrder\n            );\n\n            return this;\n        },\n\n        /**\n         * Navigate method.\n         */\n        navigate: function () {\n            var self = this;\n\n            if (!self.hasShippingMethod()) {\n                this.isVisible(false);\n                stepNavigator.setHash('shipping');\n            } else {\n                getPaymentInformation().done(function () {\n                    self.isVisible(true);\n                });\n            }\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        hasShippingMethod: function () {\n            return window.checkoutConfig.selectedShippingMethod !== null;\n        },\n\n        /**\n         * @return {*}\n         */\n        getFormKey: function () {\n            return window.checkoutConfig.formKey;\n        }\n    });\n});\n","Magento_Checkout/js/view/shipping-information.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiComponent',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/model/sidebar'\n], function ($, Component, quote, stepNavigator, sidebarModel) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/shipping-information'\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isVisible: function () {\n            return !quote.isVirtual() && stepNavigator.isProcessed('shipping');\n        },\n\n        /**\n         * @return {String}\n         */\n        getShippingMethodTitle: function () {\n            var shippingMethod = quote.shippingMethod(),\n                shippingMethodTitle = '';\n\n            if (!shippingMethod) {\n                return '';\n            }\n\n            shippingMethodTitle = shippingMethod['carrier_title'];\n\n            if (typeof shippingMethod['method_title'] !== 'undefined') {\n                shippingMethodTitle += ' - ' + shippingMethod['method_title'];\n            }\n\n            return shippingMethodTitle;\n        },\n\n        /**\n         * Back step.\n         */\n        back: function () {\n            sidebarModel.hide();\n            stepNavigator.navigateTo('shipping');\n        },\n\n        /**\n         * Back to shipping method.\n         */\n        backToShippingMethod: function () {\n            sidebarModel.hide();\n            stepNavigator.navigateTo('shipping', 'opc-shipping_method');\n        }\n    });\n});\n","Magento_Checkout/js/view/cart/shipping-estimation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n    [\n        'jquery',\n        'Magento_Ui/js/form/form',\n        'Magento_Checkout/js/action/select-shipping-address',\n        'Magento_Checkout/js/model/address-converter',\n        'Magento_Checkout/js/model/cart/estimate-service',\n        'Magento_Checkout/js/checkout-data',\n        'Magento_Checkout/js/model/shipping-rates-validator',\n        'uiRegistry',\n        'Magento_Checkout/js/model/quote',\n        'Magento_Checkout/js/model/checkout-data-resolver',\n        'Magento_Checkout/js/model/shipping-service',\n        'mage/validation'\n    ],\n    function (\n        $,\n        Component,\n        selectShippingAddress,\n        addressConverter,\n        estimateService,\n        checkoutData,\n        shippingRatesValidator,\n        registry,\n        quote,\n        checkoutDataResolver,\n        shippingService\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                template: 'Magento_Checkout/cart/shipping-estimation'\n            },\n            isVirtual: quote.isVirtual(),\n\n            /**\n             * @override\n             */\n            initialize: function () {\n                this._super();\n\n                // Prevent shipping methods showing none available whilst we resolve\n                shippingService.isLoading(true);\n\n                registry.async('checkoutProvider')(function (checkoutProvider) {\n                    var address, estimatedAddress;\n\n                    shippingService.isLoading(false);\n\n                    checkoutDataResolver.resolveEstimationAddress();\n                    address = quote.isVirtual() ? quote.billingAddress() : quote.shippingAddress();\n\n                    if (!address && quote.isVirtual()) {\n                        address = addressConverter.formAddressDataToQuoteAddress(\n                            checkoutData.getSelectedBillingAddress()\n                        );\n                    }\n\n                    if (address) {\n                        estimatedAddress = address.isEditable() ?\n                            addressConverter.quoteAddressToFormAddressData(address) :\n                            {\n                                // only the following fields must be used by estimation form data provider\n                                'country_id': address.countryId,\n                                region: address.region,\n                                'region_id': address.regionId,\n                                postcode: address.postcode\n                            };\n                        checkoutProvider.set(\n                            'shippingAddress',\n                            $.extend({}, checkoutProvider.get('shippingAddress'), estimatedAddress)\n                        );\n                    }\n\n                    if (!quote.isVirtual()) {\n                        checkoutProvider.on('shippingAddress', function (shippingAddressData) {\n                            //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n                            if (quote.shippingAddress().countryId !== shippingAddressData.country_id ||\n                                (shippingAddressData.postcode || shippingAddressData.region_id)\n                            ) {\n                                checkoutData.setShippingAddressFromData(shippingAddressData);\n                            }\n                            //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n                        });\n                    } else {\n                        checkoutProvider.on('shippingAddress', function (shippingAddressData) {\n                            checkoutData.setBillingAddressFromData(shippingAddressData);\n                        });\n                    }\n                });\n\n                return this;\n            },\n\n            /**\n             * @override\n             */\n            initElement: function (element) {\n                this._super();\n\n                if (element.index === 'address-fieldsets') {\n                    shippingRatesValidator.bindChangeHandlers(element.elems(), true, 500);\n                    element.elems.subscribe(function (elems) {\n                        shippingRatesValidator.doElementBinding(elems[elems.length - 1], true, 500);\n                    });\n                }\n\n                return this;\n            },\n\n            /**\n             * Returns shipping rates for address\n             * @returns void\n             */\n            getEstimationInfo: function () {\n                var addressData = null;\n\n                this.source.set('params.invalid', false);\n                this.source.trigger('shippingAddress.data.validate');\n\n                if (!this.source.get('params.invalid')) {\n                    addressData = this.source.get('shippingAddress');\n                    selectShippingAddress(addressConverter.formAddressDataToQuoteAddress(addressData));\n                }\n            }\n        });\n    }\n);\n","Magento_Checkout/js/view/cart/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'uiComponent',\n    'Magento_Checkout/js/model/totals',\n    'Magento_Checkout/js/model/shipping-service'\n], function ($, Component, totalsService, shippingService) {\n    'use strict';\n\n    return Component.extend({\n        isLoading: totalsService.isLoading,\n\n        /**\n         * @override\n         */\n        initialize: function () {\n            this._super();\n            totalsService.totals.subscribe(function () {\n                $(window).trigger('resize');\n            });\n            shippingService.getShippingRates().subscribe(function () {\n                $(window).trigger('resize');\n            });\n        }\n    });\n});\n","Magento_Checkout/js/view/cart/shipping-rates.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'uiComponent',\n    'Magento_Checkout/js/model/shipping-service',\n    'Magento_Catalog/js/price-utils',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/action/select-shipping-method',\n    'Magento_Checkout/js/checkout-data'\n], function (ko, _, Component, shippingService, priceUtils, quote, selectShippingMethodAction, checkoutData) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/cart/shipping-rates'\n        },\n        isVisible: ko.observable(!quote.isVirtual()),\n        isLoading: shippingService.isLoading,\n        shippingRates: shippingService.getShippingRates(),\n        shippingRateGroups: ko.observableArray([]),\n        selectedShippingMethod: ko.computed(function () {\n            return quote.shippingMethod() ?\n                quote.shippingMethod()['carrier_code'] + '_' + quote.shippingMethod()['method_code'] :\n                null;\n        }),\n\n        /**\n         * @override\n         */\n        initObservable: function () {\n            var self = this;\n\n            this._super();\n\n            this.shippingRates.subscribe(function (rates) {\n                self.shippingRateGroups([]);\n                _.each(rates, function (rate) {\n                    var carrierTitle = rate['carrier_title'];\n\n                    if (self.shippingRateGroups.indexOf(carrierTitle) === -1) {\n                        self.shippingRateGroups.push(carrierTitle);\n                    }\n                });\n            });\n\n            return this;\n        },\n\n        /**\n         * Get shipping rates for specific group based on title.\n         * @returns Array\n         */\n        getRatesForGroup: function (shippingRateGroupTitle) {\n            return _.filter(this.shippingRates(), function (rate) {\n                return shippingRateGroupTitle === rate['carrier_title'];\n            });\n        },\n\n        /**\n         * Format shipping price.\n         * @returns {String}\n         */\n        getFormattedPrice: function (price) {\n            return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n        },\n\n        /**\n         * Set shipping method.\n         * @param {String} methodData\n         * @returns bool\n         */\n        selectShippingMethod: function (methodData) {\n            selectShippingMethodAction(methodData);\n            checkoutData.setSelectedShippingRate(methodData['carrier_code'] + '_' + methodData['method_code']);\n\n            return true;\n        }\n    });\n});\n","Magento_Checkout/js/view/cart/totals/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/shipping',\n    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    return Component.extend({\n\n        /**\n         * @override\n         */\n        isCalculated: function () {\n            return !!quote.shippingMethod();\n        }\n    });\n});\n","Magento_Checkout/js/view/checkout/placeOrderCaptcha.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Captcha/js/view/checkout/defaultCaptcha',\n    'Magento_Captcha/js/model/captchaList',\n    'underscore',\n    'Magento_Checkout/js/model/payment/place-order-hooks'\n],\nfunction (defaultCaptcha, captchaList, _, placeOrderHooks) {\n    'use strict';\n\n    return defaultCaptcha.extend({\n        /** @inheritdoc */\n        initialize: function () {\n            var self = this,\n                currentCaptcha;\n\n            this._super();\n            currentCaptcha = captchaList.getCaptchaByFormId(this.formId);\n            if (currentCaptcha != null) {\n                currentCaptcha.setIsVisible(true);\n                this.setCurrentCaptcha(currentCaptcha);\n                placeOrderHooks.requestModifiers.push(function (headers) {\n                    if (self.isRequired()) {\n                        headers['X-Captcha'] = self.captchaValue()();\n                    }\n                });\n                if (self.isRequired()) {\n                    placeOrderHooks.afterRequestListeners.push(function () {\n                        self.refresh();\n                    });\n                }\n            }\n        }\n    });\n});\n","Magento_Checkout/js/view/checkout/minicart/subtotal/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'uiComponent',\n    'Magento_Customer/js/customer-data'\n], function (ko, Component, customerData) {\n    'use strict';\n\n    return Component.extend({\n        displaySubtotal: ko.observable(true),\n\n        /**\n         * @override\n         */\n        initialize: function () {\n            this._super();\n            this.cart = customerData.get('cart');\n        }\n    });\n});\n","Magento_Checkout/js/view/shipping-address/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'ko',\n    'mageUtils',\n    'uiComponent',\n    'uiLayout',\n    'Magento_Customer/js/model/address-list'\n], function (_, ko, utils, Component, layout, addressList) {\n    'use strict';\n\n    var defaultRendererTemplate = {\n        parent: '${ $.$data.parentName }',\n        name: '${ $.$data.name }',\n        component: 'Magento_Checkout/js/view/shipping-address/address-renderer/default',\n        provider: 'checkoutProvider'\n    };\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/shipping-address/list',\n            visible: addressList().length > 0,\n            rendererTemplates: []\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super()\n                .initChildren();\n\n            addressList.subscribe(function (changes) {\n                    var self = this;\n\n                    changes.forEach(function (change) {\n                        if (change.status === 'added') {\n                            self.createRendererComponent(change.value, change.index);\n                        }\n                    });\n                },\n                this,\n                'arrayChange'\n            );\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initConfig: function () {\n            this._super();\n            // the list of child components that are responsible for address rendering\n            this.rendererComponents = [];\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initChildren: function () {\n            _.each(addressList(), this.createRendererComponent, this);\n\n            return this;\n        },\n\n        /**\n         * Create new component that will render given address in the address list\n         *\n         * @param {Object} address\n         * @param {*} index\n         */\n        createRendererComponent: function (address, index) {\n            var rendererTemplate, templateData, rendererComponent;\n\n            if (index in this.rendererComponents) {\n                this.rendererComponents[index].address(address);\n            } else {\n                // rendererTemplates are provided via layout\n                rendererTemplate = address.getType() != undefined && this.rendererTemplates[address.getType()] != undefined ? //eslint-disable-line\n                    utils.extend({}, defaultRendererTemplate, this.rendererTemplates[address.getType()]) :\n                    defaultRendererTemplate;\n                templateData = {\n                    parentName: this.name,\n                    name: index\n                };\n                rendererComponent = utils.template(rendererTemplate, templateData);\n                utils.extend(rendererComponent, {\n                    address: ko.observable(address)\n                });\n                layout([rendererComponent]);\n                this.rendererComponents[index] = rendererComponent;\n            }\n        }\n    });\n});\n","Magento_Checkout/js/view/shipping-address/address-renderer/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'uiComponent',\n    'underscore',\n    'Magento_Checkout/js/action/select-shipping-address',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/shipping-address/form-popup-state',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Customer/js/customer-data'\n], function ($, ko, Component, _, selectShippingAddressAction, quote, formPopUpState, checkoutData, customerData) {\n    'use strict';\n\n    var countryData = customerData.get('directory-data');\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/shipping-address/address-renderer/default'\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super();\n            this.isSelected = ko.computed(function () {\n                var isSelected = false,\n                    shippingAddress = quote.shippingAddress();\n\n                if (shippingAddress) {\n                    isSelected = shippingAddress.getKey() == this.address().getKey(); //eslint-disable-line eqeqeq\n                }\n\n                return isSelected;\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * @param {String} countryId\n         * @return {String}\n         */\n        getCountryName: function (countryId) {\n            return countryData()[countryId] != undefined ? countryData()[countryId].name : ''; //eslint-disable-line\n        },\n\n        /**\n         * Get customer attribute label\n         *\n         * @param {*} attribute\n         * @returns {*}\n         */\n        getCustomAttributeLabel: function (attribute) {\n            var label;\n\n            if (typeof attribute === 'string') {\n                return attribute;\n            }\n\n            if (attribute.label) {\n                return attribute.label;\n            }\n\n            if (_.isArray(attribute.value)) {\n                label = _.map(attribute.value, function (value) {\n                    return this.getCustomAttributeOptionLabel(attribute['attribute_code'], value) || value;\n                }, this).join(', ');\n            } else if (typeof attribute.value === 'object') {\n                label = _.map(Object.values(attribute.value)).join(', ');\n            } else {\n                label = this.getCustomAttributeOptionLabel(attribute['attribute_code'], attribute.value);\n            }\n\n            return label || attribute.value;\n        },\n\n        /**\n         * Get option label for given attribute code and option ID\n         *\n         * @param {String} attributeCode\n         * @param {String} value\n         * @returns {String|null}\n         */\n        getCustomAttributeOptionLabel: function (attributeCode, value) {\n            var option,\n                label,\n                options = this.source.get('customAttributes') || {};\n\n            if (options[attributeCode]) {\n                option = _.findWhere(options[attributeCode], {\n                    value: value\n                });\n\n                if (option) {\n                    label = option.label;\n                }\n            } else if (value.file !== null) {\n                label = value.file;\n            }\n\n            return label;\n        },\n\n        /** Set selected customer shipping address  */\n        selectAddress: function () {\n            selectShippingAddressAction(this.address());\n            checkoutData.setSelectedShippingAddress(this.address().getKey());\n        },\n\n        /**\n         * Edit address.\n         */\n        editAddress: function () {\n            formPopUpState.isVisible(true);\n            this.showPopup();\n\n        },\n\n        /**\n         * Show popup.\n         */\n        showPopup: function () {\n            $('[data-open-modal=\"opc-new-shipping-address\"]').trigger('click');\n        }\n    });\n});\n","Magento_Checkout/js/view/payment/email-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n    [\n        'uiComponent',\n        'Magento_Checkout/js/model/payment/additional-validators',\n        'Magento_Checkout/js/model/customer-email-validator'\n    ],\n    function (Component, additionalValidators, agreementValidator) {\n        'use strict';\n\n        additionalValidators.registerValidator(agreementValidator);\n\n        return Component.extend({});\n    }\n);\n","Magento_Checkout/js/view/payment/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'jquery',\n    'uiComponent',\n    'Magento_Checkout/js/action/place-order',\n    'Magento_Checkout/js/action/select-payment-method',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Customer/js/model/customer',\n    'Magento_Checkout/js/model/payment-service',\n    'Magento_Checkout/js/checkout-data',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'uiRegistry',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Ui/js/model/messages',\n    'uiLayout',\n    'Magento_Checkout/js/action/redirect-on-success'\n], function (\n    ko,\n    $,\n    Component,\n    placeOrderAction,\n    selectPaymentMethodAction,\n    quote,\n    customer,\n    paymentService,\n    checkoutData,\n    checkoutDataResolver,\n    registry,\n    additionalValidators,\n    Messages,\n    layout,\n    redirectOnSuccessAction\n) {\n    'use strict';\n\n    return Component.extend({\n        redirectAfterPlaceOrder: true,\n        isPlaceOrderActionAllowed: ko.observable(quote.billingAddress() != null),\n\n        /**\n         * After place order callback\n         */\n        afterPlaceOrder: function () {\n            // Override this function and put after place order logic here\n        },\n\n        /**\n         * Initialize view.\n         *\n         * @return {exports}\n         */\n        initialize: function () {\n            var billingAddressCode,\n                billingAddressData,\n                defaultAddressData;\n\n            this._super().initChildren();\n            quote.billingAddress.subscribe(function (address) {\n                this.isPlaceOrderActionAllowed(address !== null);\n            }, this);\n            checkoutDataResolver.resolveBillingAddress();\n\n            billingAddressCode = 'billingAddress' + this.getCode();\n            registry.async('checkoutProvider')(function (checkoutProvider) {\n                defaultAddressData = checkoutProvider.get(billingAddressCode);\n\n                if (defaultAddressData === undefined) {\n                    // Skip if payment does not have a billing address form\n                    return;\n                }\n                billingAddressData = checkoutData.getBillingAddressFromData();\n\n                if (billingAddressData) {\n                    checkoutProvider.set(\n                        billingAddressCode,\n                        $.extend(true, {}, defaultAddressData, billingAddressData)\n                    );\n                }\n                checkoutProvider.on(billingAddressCode, function (providerBillingAddressData) {\n                    checkoutData.setBillingAddressFromData(providerBillingAddressData);\n                }, billingAddressCode);\n            });\n\n            return this;\n        },\n\n        /**\n         * Initialize child elements\n         *\n         * @returns {Component} Chainable.\n         */\n        initChildren: function () {\n            this.messageContainer = new Messages();\n            this.createMessagesComponent();\n\n            return this;\n        },\n\n        /**\n         * Create child message renderer component\n         *\n         * @returns {Component} Chainable.\n         */\n        createMessagesComponent: function () {\n\n            var messagesComponent = {\n                parent: this.name,\n                name: this.name + '.messages',\n                displayArea: 'messages',\n                component: 'Magento_Ui/js/view/messages',\n                config: {\n                    messageContainer: this.messageContainer\n                }\n            };\n\n            layout([messagesComponent]);\n\n            return this;\n        },\n\n        /**\n         * Place order.\n         */\n        placeOrder: function (data, event) {\n            var self = this;\n\n            if (event) {\n                event.preventDefault();\n            }\n\n            if (this.validate() &&\n                additionalValidators.validate() &&\n                this.isPlaceOrderActionAllowed() === true\n            ) {\n                this.isPlaceOrderActionAllowed(false);\n\n                this.getPlaceOrderDeferredObject()\n                    .done(\n                        function () {\n                            self.afterPlaceOrder();\n\n                            if (self.redirectAfterPlaceOrder) {\n                                redirectOnSuccessAction.execute();\n                            }\n                        }\n                    ).always(\n                        function () {\n                            self.isPlaceOrderActionAllowed(true);\n                        }\n                    );\n\n                return true;\n            }\n\n            return false;\n        },\n\n        /**\n         * @return {*}\n         */\n        getPlaceOrderDeferredObject: function () {\n            return $.when(\n                placeOrderAction(this.getData(), this.messageContainer)\n            );\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        selectPaymentMethod: function () {\n            selectPaymentMethodAction(this.getData());\n            checkoutData.setSelectedPaymentMethod(this.item.method);\n\n            return true;\n        },\n\n        isChecked: ko.computed(function () {\n            return quote.paymentMethod() ? quote.paymentMethod().method : null;\n        }),\n\n        isRadioButtonVisible: ko.computed(function () {\n            return paymentService.getAvailablePaymentMethods().length !== 1;\n        }),\n\n        /**\n         * Get payment method data\n         */\n        getData: function () {\n            return {\n                'method': this.item.method,\n                'po_number': null,\n                'additional_data': null\n            };\n        },\n\n        /**\n         * Get payment method type.\n         */\n        getTitle: function () {\n            return this.item.title;\n        },\n\n        /**\n         * Get payment method code.\n         */\n        getCode: function () {\n            return this.item.method;\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        validate: function () {\n            return true;\n        },\n\n        /**\n         * @return {String}\n         */\n        getBillingAddressFormName: function () {\n            return 'billing-address-form-' + this.item.method;\n        },\n\n        /**\n         * Dispose billing address subscriptions\n         */\n        disposeSubscriptions: function () {\n            // dispose all active subscriptions\n            var billingAddressCode = 'billingAddress' + this.getCode();\n\n            registry.async('checkoutProvider')(function (checkoutProvider) {\n                checkoutProvider.off(billingAddressCode);\n            });\n        }\n    });\n});\n","Magento_Checkout/js/view/payment/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'ko',\n    'mageUtils',\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/method-list',\n    'Magento_Checkout/js/model/payment/renderer-list',\n    'uiLayout',\n    'Magento_Checkout/js/model/checkout-data-resolver',\n    'mage/translate',\n    'uiRegistry'\n], function (_, ko, utils, Component, paymentMethods, rendererList, layout, checkoutDataResolver, $t, registry) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/payment-methods/list',\n            visible: paymentMethods().length > 0,\n            configDefaultGroup: {\n                name: 'methodGroup',\n                component: 'Magento_Checkout/js/model/payment/method-group'\n            },\n            paymentGroupsList: [],\n            defaultGroupTitle: $t('Select a new payment method')\n        },\n\n        /**\n         * Initialize view.\n         *\n         * @returns {Component} Chainable.\n         */\n        initialize: function () {\n            this._super().initDefaulGroup().initChildren();\n            paymentMethods.subscribe(\n                function (changes) {\n                    checkoutDataResolver.resolvePaymentMethod();\n                    //remove renderer for \"deleted\" payment methods\n                    _.each(changes, function (change) {\n                        if (change.status === 'deleted') {\n                            this.removeRenderer(change.value.method);\n                        }\n                    }, this);\n                    //add renderer for \"added\" payment methods\n                    _.each(changes, function (change) {\n                        if (change.status === 'added') {\n                            this.createRenderer(change.value);\n                        }\n                    }, this);\n                }, this, 'arrayChange');\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super().\n                observe(['paymentGroupsList']);\n\n            return this;\n        },\n\n        /**\n         * Creates default group\n         *\n         * @returns {Component} Chainable.\n         */\n        initDefaulGroup: function () {\n            layout([\n                this.configDefaultGroup\n            ]);\n\n            return this;\n        },\n\n        /**\n         * Create renders for child payment methods.\n         *\n         * @returns {Component} Chainable.\n         */\n        initChildren: function () {\n            var self = this;\n\n            _.each(paymentMethods(), function (paymentMethodData) {\n                self.createRenderer(paymentMethodData);\n            });\n\n            return this;\n        },\n\n        /**\n         * @returns\n         */\n        createComponent: function (payment) {\n            var rendererTemplate,\n                rendererComponent,\n                templateData;\n\n            templateData = {\n                parentName: this.name,\n                name: payment.name\n            };\n            rendererTemplate = {\n                parent: '${ $.$data.parentName }',\n                name: '${ $.$data.name }',\n                displayArea: payment.displayArea,\n                component: payment.component\n            };\n            rendererComponent = utils.template(rendererTemplate, templateData);\n            utils.extend(rendererComponent, {\n                item: payment.item,\n                config: payment.config\n            });\n\n            return rendererComponent;\n        },\n\n        /**\n         * Create renderer.\n         *\n         * @param {Object} paymentMethodData\n         */\n        createRenderer: function (paymentMethodData) {\n            var isRendererForMethod = false,\n                currentGroup;\n\n            registry.get(this.configDefaultGroup.name, function (defaultGroup) {\n                _.each(rendererList(), function (renderer) {\n\n                    if (renderer.hasOwnProperty('typeComparatorCallback') &&\n                        typeof renderer.typeComparatorCallback == 'function'\n                    ) {\n                        isRendererForMethod = renderer.typeComparatorCallback(renderer.type, paymentMethodData.method);\n                    } else {\n                        isRendererForMethod = renderer.type === paymentMethodData.method;\n                    }\n\n                    if (isRendererForMethod) {\n                        currentGroup = renderer.group ? renderer.group : defaultGroup;\n\n                        this.collectPaymentGroups(currentGroup);\n\n                        layout([\n                            this.createComponent(\n                                {\n                                    config: renderer.config,\n                                    component: renderer.component,\n                                    name: renderer.type,\n                                    method: paymentMethodData.method,\n                                    item: paymentMethodData,\n                                    displayArea: currentGroup.displayArea\n                                }\n                            )]);\n                    }\n                }.bind(this));\n            }.bind(this));\n        },\n\n        /**\n         * Collects unique groups of available payment methods\n         *\n         * @param {Object} group\n         */\n        collectPaymentGroups: function (group) {\n            var groupsList = this.paymentGroupsList(),\n                isGroupExists = _.some(groupsList, function (existsGroup) {\n                    return existsGroup.alias === group.alias;\n                });\n\n            if (!isGroupExists) {\n                groupsList.push(group);\n                groupsList = _.sortBy(groupsList, function (existsGroup) {\n                    return existsGroup.sortOrder;\n                });\n                this.paymentGroupsList(groupsList);\n            }\n        },\n\n        /**\n         * Returns payment group title\n         *\n         * @param {Object} group\n         * @returns {String}\n         */\n        getGroupTitle: function (group) {\n            var title = group().title;\n\n            if (group().isDefault() && this.paymentGroupsList().length > 1) {\n                title = this.defaultGroupTitle;\n            }\n\n            return title;\n        },\n\n        /**\n         * Checks if at least one payment method available\n         *\n         * @returns {String}\n         */\n        isPaymentMethodsAvailable: function () {\n            return _.some(this.paymentGroupsList(), function (group) {\n                return this.regionHasElements(group.displayArea);\n            }, this);\n        },\n\n        /**\n         * Remove view renderer.\n         *\n         * @param {String} paymentMethodCode\n         */\n        removeRenderer: function (paymentMethodCode) {\n            var items;\n\n            _.each(this.paymentGroupsList(), function (group) {\n                items = this.getRegion(group.displayArea);\n\n                _.find(items(), function (value) {\n                    if (value.item.method.indexOf(paymentMethodCode) === 0) {\n                        value.disposeSubscriptions();\n                        value.destroy();\n                    }\n                });\n            }, this);\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/cart-items.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_Checkout/js/model/totals',\n    'uiComponent',\n    'Magento_Checkout/js/model/step-navigator',\n    'Magento_Checkout/js/model/quote'\n], function (ko, totals, Component, stepNavigator, quote) {\n    'use strict';\n\n    var useQty = window.checkoutConfig.useQty;\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/summary/cart-items'\n        },\n        totals: totals.totals(),\n        items: ko.observable([]),\n        maxCartItemsToDisplay: window.checkoutConfig.maxCartItemsToDisplay,\n        cartUrl: window.checkoutConfig.cartUrl,\n\n        /**\n         * @deprecated Please use observable property (this.items())\n         */\n        getItems: totals.getItems(),\n\n        /**\n         * Returns cart items qty\n         *\n         * @returns {Number}\n         */\n        getItemsQty: function () {\n            return parseFloat(this.totals['items_qty']);\n        },\n\n        /**\n         * Returns count of cart line items\n         *\n         * @returns {Number}\n         */\n        getCartLineItemsCount: function () {\n            return parseInt(totals.getItems()().length, 10);\n        },\n\n        /**\n         * Returns shopping cart items summary (includes config settings)\n         *\n         * @returns {Number}\n         */\n        getCartSummaryItemsCount: function () {\n            return useQty ? this.getItemsQty() : this.getCartLineItemsCount();\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function () {\n            this._super();\n            // Set initial items to observable field\n            this.setItems(totals.getItems()());\n            // Subscribe for items data changes and refresh items in view\n            totals.getItems().subscribe(function (items) {\n                this.setItems(items);\n            }.bind(this));\n        },\n\n        /**\n         * Set items to observable field\n         *\n         * @param {Object} items\n         */\n        setItems: function (items) {\n            if (items && items.length > 0) {\n                items = items.slice(parseInt(-this.maxCartItemsToDisplay, 10));\n            }\n            this.items(items);\n        },\n\n        /**\n         * Returns bool value for items block state (expanded or not)\n         *\n         * @returns {*|Boolean}\n         */\n        isItemsBlockExpanded: function () {\n            return quote.isVirtual() || stepNavigator.isProcessed('shipping');\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/abstract-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Catalog/js/price-utils',\n    'Magento_Checkout/js/model/totals',\n    'Magento_Checkout/js/model/step-navigator'\n], function (Component, quote, priceUtils, totals, stepNavigator) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @param {*} price\n         * @return {*|String}\n         */\n        getFormattedPrice: function (price) {\n            return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n        },\n\n        /**\n         * @return {*}\n         */\n        getTotals: function () {\n            return totals.totals();\n        },\n\n        /**\n         * @return {*}\n         */\n        isFullMode: function () {\n            if (!this.getTotals()) {\n                return false;\n            }\n\n            return stepNavigator.isProcessed('shipping');\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/summary/subtotal'\n        },\n\n        /**\n         * Get pure value.\n         *\n         * @return {*}\n         */\n        getPureValue: function () {\n            var totals = quote.getTotals()();\n\n            if (totals) {\n                return totals.subtotal;\n            }\n\n            return quote.subtotal;\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getValue: function () {\n            return this.getFormattedPrice(this.getPureValue());\n        }\n\n    });\n});\n","Magento_Checkout/js/view/summary/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @return {*}\n         */\n        isDisplayed: function () {\n            return this.isFullMode();\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/summary/grand-total'\n        },\n\n        /**\n         * @return {*}\n         */\n        isDisplayed: function () {\n            return this.isFullMode();\n        },\n\n        /**\n         * Get pure value.\n         */\n        getPureValue: function () {\n            var totals = quote.getTotals()();\n\n            if (totals) {\n                return totals['grand_total'];\n            }\n\n            return quote['grand_total'];\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getValue: function () {\n            return this.getFormattedPrice(this.getPureValue());\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote',\n    'Magento_SalesRule/js/view/summary/discount'\n], function ($, _, Component, quote, discountView) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/summary/shipping'\n        },\n        quoteIsVirtual: quote.isVirtual(),\n        totals: quote.getTotals(),\n\n        /**\n         * @return {*}\n         */\n        getShippingMethodTitle: function () {\n            var shippingMethod,\n                shippingMethodTitle = '';\n\n            if (!this.isCalculated()) {\n                return '';\n            }\n            shippingMethod = quote.shippingMethod();\n\n            if (!_.isArray(shippingMethod) && !_.isObject(shippingMethod)) {\n                return '';\n            }\n\n            if (typeof shippingMethod['method_title'] !== 'undefined') {\n                shippingMethodTitle = ' - ' + shippingMethod['method_title'];\n            }\n\n            return shippingMethodTitle ?\n                shippingMethod['carrier_title'] + shippingMethodTitle :\n                shippingMethod['carrier_title'];\n        },\n\n        /**\n         * @return {*|Boolean}\n         */\n        isCalculated: function () {\n            return this.totals() && this.isFullMode() && quote.shippingMethod() != null; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {*}\n         */\n        getValue: function () {\n            var price;\n\n            if (!this.isCalculated()) {\n                return this.notCalculatedMessage;\n            }\n            price =  this.totals()['shipping_amount'];\n\n            return this.getFormattedPrice(price);\n        },\n\n        /**\n         * If is set coupon code, but there wasn't displayed discount view.\n         *\n         * @return {Boolean}\n         */\n        haveToShowCoupon: function () {\n            var couponCode = this.totals()['coupon_code'];\n\n            if (typeof couponCode === 'undefined') {\n                couponCode = false;\n            }\n\n            return couponCode && !discountView().isDisplayed();\n        },\n\n        /**\n         * Returns coupon code description.\n         *\n         * @return {String}\n         */\n        getCouponDescription: function () {\n            if (!this.haveToShowCoupon()) {\n                return '';\n            }\n\n            return '(' + this.totals()['coupon_code'] + ')';\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/item/details.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'escaper'\n], function (Component, escaper) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Checkout/summary/item/details',\n            allowedTags: ['b', 'strong', 'i', 'em', 'u']\n        },\n\n        /**\n         * @param {Object} quoteItem\n         * @return {String}\n         */\n        getNameUnsanitizedHtml: function (quoteItem) {\n            var txt = document.createElement('textarea');\n\n            txt.innerHTML = quoteItem.name;\n\n            return escaper.escapeHtml(txt.value, this.allowedTags);\n        },\n\n        /**\n         * @param {Object} quoteItem\n         * @return {String}Magento_Checkout/js/region-updater\n         */\n        getValue: function (quoteItem) {\n            return quoteItem.name;\n        }\n    });\n});\n","Magento_Checkout/js/view/summary/item/details/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total'\n], function (viewModel) {\n    'use strict';\n\n    return viewModel.extend({\n        defaults: {\n            displayArea: 'after_details',\n            template: 'Magento_Checkout/summary/item/details/subtotal'\n        },\n\n        /**\n         * @param {Object} quoteItem\n         * @return {*|String}\n         */\n        getValue: function (quoteItem) {\n            return this.getFormattedPrice(quoteItem['row_total']);\n        }\n    });\n});\n"}
}});

Spamworldpro Mini