���� JFIF  XX �� �� �     $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222�� ��" �� 4     ��   �� �,�PG"Z_�4�˷����kjز�Z�,F+��_z�,�© �����zh6�٨�ic�fu��� #ډb���_�N� ?� �wQ���5-�~�I���8��� �TK<5o�Iv-� ����k�_U_����� ~b�M��d��� �Ӝ�U�Hh��?]��E�w��Q���k�{��_}qFW7HTՑ��Y��F� ?_�'ϔ��_�Ջt� �=||I �� 6�έ"�����D���/[�k�9�� �Y�8 ds|\���Ҿp6�Ҵ���]��.����6� z<�v��@]�i% �� $j��~ �g��J>��no����pM[me�i$[�� �� s�o�ᘨ�˸ nɜG-�ĨU�ycP� 3.DB�li�;� �hj���x 7Z^�N�h��� ���N3u{�:j �x�힞��#M &��jL P@ _���� P�� &��o8 ������9 �����@Sz 6�t7#O�ߋ � s}Yf�T� ��lmr����Z)'N��k�۞p ����w\�T ȯ?�8` �O��i{wﭹW�[�r�� ��Q4F�׊�� �3m&L�=��h3� ���z~��#� \�l :�F,j@�� ʱ�wQT����8�"kJO��� 6�֚l���� }��� R�>ډK���]��y����&����p�}b�� ;N�1�m�r$� |��7�>e�@ B�TM*-i H��g�D�)� E�m�|�ؘbҗ�a ��Ҿ���� t4��� o���G��*oCN�rP���Q��@z,|?W[0 �����:�n,j WiE��W� �$~/�hp\��?��{(�0���+�Y8rΟ�+����>S-S�� ��VN;� }�s?.����� w �9��˟<���Mq4�Wv' ��{)0�1mB ��V����W[� ����8�/<� �%���wT^�5���b��)iM� p g�N�&ݝ� �VO~� q���u���9� ����!��J27��� �$ O-���! �: �%H��� ـ ����y�ΠM=t{!S�� oK8������ t<����è :a�� ����[���� �ա�H���~��w��Qz`�p o�^ �� ��Q��n�  �,uu�C� $ ^���,� �����8�#��:�6��e�|~� ��!�3� 3.�\0�� q��o�4`.|� ����y�Q�`~;�d�ׯ,��O�Zw�������`73�v�܋�< ���Ȏ�� ـ4k��5�K�a�u�=9Yd��$>x�A�&�� j0� ���vF��� Y� |�y��� ~�6�@c��1vOp �Ig�� ��4��l�OD� ��L����� R���c���j�_�uX 6��3?nk��Wy�f;^*B� ��@ �~a�`��Eu������ +� �� 6�L��.ü>��}y���}_�O�6�͐�:�Yr G�X��kG�� ���l^w�� �~㒶sy� �Iu�!� W ��X��N�7BV��O��!X�2����wvG�R�f�T#�����t�/?���%8�^�W�aT ��G�cL�M���I��(J����1~�8�?aT ���]����AS�E��(��*E}� 2�� #I/�׍qz��^t�̔��� b�Yz4x ���t�){ OH� �+(E��A&�N�������XT��o��"�XC�� '���)}�J�z�p� ��~5�}�^����+�6����w��c��Q�| Lp�d�H��}�(�.|����k��c4^� "�����Z?ȕ ��a< �L�!0 39C� �Eu� C�F�Ew�ç ;�n?�*o���B�8�bʝ���'#Rqf�� �M}7����]��� �s2tcS{�\icTx;�\��7K���P ���ʇ Z O-��~�� c>"��?�� �����P ��E��O�8��@�8��G��Q�g�a�Վ���󁶠 �䧘��_%#r�>� 1�z�a�� eb��qcP ѵ��n���#L��� =��׀t� L�7�` ��V��� A{�C:�g���e@ �w1 Xp 3�c3�ġ���� p��M"'-�@n4���fG� �B3�DJ�8[Jo�ߐ���gK)ƛ��$���� � ��8�3�����+���� �����6�ʻ���� ���S�kI�*KZlT _`�� �?��K� ���QK�d ����B`�s}�>���` ��*�>��,*@J�d�oF*� ���弝��O}�k��s��]��y�ߘ ��c1G�V���<=�7��7����6 �q�PT��tXԀ�!9*4�4Tހ 3XΛex�46�� �Y��D ����� �BdemDa����\�_l,� �G�/���֌7���Y�](�xTt^%�GE�����4�}bT ���ڹ�����; Y)���B�Q��u��>J/J � ⮶.�XԄ��j�ݳ� +E��d ��r�5�_D �1 �� o�� �B�x�΢�#� ��<��W�����8���R6�@ g�M�.��� dr�D��>(otU��@ x=��~v���2� ӣ�d�oBd ��3�eO�6�㣷�� ���ݜ 6��6Y��Qz`�� S��{���\P �~z m5{J/L��1������<�e�ͅPu� b�]�ϔ ���'�� ����f�b� Zpw��c`"��i���BD@:)ִ�:�]��h v�E� w���T�l ��P� ��"Ju�}��وV J��G6��. J/�Qgl߭�e�����@�z�Zev2u� )]կ��� ��7x�� �s�M�-<ɯ�c��r� v�����@��$�ޮ}lk���a�� �'����>x��O\�Z Fu>��� ��ck#��&:��`�$ �ai�>2Δ����l���oF[h� �lE�ܺ�Π k:)���` �� $[6�����9�����kOw�\|��� 8}������ބ:��񶐕� �I�A1/� =�2[�,�!��.}gN#�u����b ��� ~� �݊��}34q��� �d�E��L c��$ ��"�[q�U�硬g^��%B � z���r�p J�ru%v\h 1Y�ne` ǥ:g�� �pQM~�^� Xi� ��`S�:V2 9.�P���V� ?B�k�� AEvw%�_�9C�Q����wKekP ؠ�\� ;Io d�{ ߞo�c1eP��� �\� `����E=���@K<�Y�� �eڼ�J ���w����{av�F�'�M�@ /J��+9p ���|]���� �Iw &` ��8���& M�hg ��[�{ ��Xj�� %��Ӓ� $��(��� �ʹN��� <>�I���RY� ��K2�NPlL�ɀ )��&e� ���B+ь����( � �JTx ���_?EZ� }@ 6�U���뙢ط�z��dWI� n` D����噥�[��uV��"�G& Ú����2 g�}&m� �?ċ �"����Om#� ������� � ��{� ON��"S�X ��Ne��ysQ���@ Fn��Vg��� dX�~nj� ]J�<�K]: ��FW�� b�������62 �=��5f����JKw� �bf�X� 55��~J �%^� ���:�-�QIE��P��v�nZum� z � ~ə ���� ���ة����;�f��\v��� g�8�1��f2 4;�V���ǔ�)��� �9���1\�� c��v�/'Ƞ�w����� ��$�4�R-��t�� �� e�6�/�ġ �̕Ecy�J���u�B���<�W�ַ~�w[B1L۲�-JS΂�{���΃���� ��A��20�c# �� @    0!1@AP"#2Q`$3V�%45a6�FRUq���   � ���^7ׅ,$n� ������+��F�`��2X'��0vM��p�L=������ 5��8������u�p~���.�`r�����\��� O��,ư�0oS ��_�M�����l���4�kv\JSd���x���SW�<��Ae�IX����������$I���w�:S���y���›R��9�Q[���,�5�;�@]�%���u�@ *ro�lbI �� ��+���%m:�͇ZV�����u�̉����θau<�fc�.����{�4Ա� �Q����*�Sm��8\ujqs]{kN���)qO�y�_*dJ�b�7���yQqI&9�ԌK!�M}�R�;�� ����S�T���1���i[U�ɵz�]��U)V�S6���3$K{� ߊ<�(� E]Զ[ǼENg�����'�\?#)Dkf��J���o��v���'�%ƞ�&K�u� !��b�35LX�Ϸ��63$K�a�;�9>,R��W��3�3� d�JeTYE.Mϧ��-�o�j3+y��y^�c�������VO�9NV\nd�1 ��!͕_)a�v;����թ�M�lWR1��)El��P;��yوÏ�u 3�k�5Pr6<�⒲l�!˞*��u־�n�!�l:����UNW ��%��Chx8vL'��X�@��*��)���̮��ˍ��� � ��D-M�+J�U�kvK����+�x8��cY������?�Ԡ��~3mo��|�u@[XeY�C�\Kp�x8�oC�C�&����N�~3-H���� ��MX�s�u<`���~"WL��$8ξ��3���a�)|:@�m�\���^�`�@ҷ)�5p+��6���p�%i)P M���ngc�����#0Aruz���RL+xSS?���ʮ}()#�t��mˇ!��0}}y����<�e� �-ή�Ԩ��X������ MF���ԙ~l L.3���}�V뽺�v��� ��멬��Nl�)�2����^�Iq��a��M��qG��T�����c3#������3U�Ǎ���}��לS�|qa��ڃ�+���-��2�f����/��bz��ڐ�� �ݼ[2�ç����k�X�2�* �Z�d���J�G����M*9W���s{��w���T��x��y,�in�O�v��]���n����P�$� JB@=4�OTI�n��e�22a\����q�d���%�$��(���:���: /*�K[PR�fr\nڙdN���F�n�$�4� [�� U�zƶ����� �mʋ���,�ao�u 3�z� �x��Kn����\[��VFmbE;�_U��&V�Gg�]L�۪&#n%�$ɯ� dG���D�TI=�%+AB�Ru#��b4�1�»x�cs�YzڙJG��f��Il� �d�eF'T� iA��T���uC�$����Y��H?����[!G`}���ͪ� �纤Hv\������j�Ex�K���!���OiƸ�Yj�+u-<���'q����uN�*�r\��+�]���<�wOZ.fp�ێ��,-*)V?j-kÊ#�`�r��dV����(�ݽBk�����G�ƛk�QmUڗe��Z���f}|����8�8��a���i��3'J�����~G_�^���d�8w������ R�`(�~�.��u���l�s+g�bv���W���lGc}��u���afE~1�Ue������Z�0�8�=e�� f@/�jqEKQQ�J� �oN��J���W5~M>$6�Lt�;$ʳ{���^��6�{����v6���ķܰg�V�cnn �~z�x�«�,2�u�?cE+Ș�H؎�%�Za�)���X>uW�Tz�Nyo����s���FQƤ��$��*�&�LLXL)�1�" L��eO��ɟ�9=���:t��Z���c��Ž���Y?�ӭV�wv�~,Y��r�ۗ�|�y��GaF�����C�����.�+� ���v1���fήJ�����]�S��T��B��n5sW}y�$��~z�'�c ��8 ��� ,! �p��VN�S��N�N�q��y8z˱�A��4��*��'������2n<�s���^ǧ˭P�Jޮɏ�U�G�L�J�*#��<�V��t7�8����TĜ>��i}K%,���)[��z�21z ?�N�i�n1?T�I�R#��m-�����������������1����lA�`��fT5+��ܐ�c�q՝��ʐ��,���3�f2U�եmab��#ŠdQ�y>\��)�SLY����w#��.���ʑ�f��� ,"+�w�~�N�'�c�O�3F�������N<���)j��&��,-� �љ���֊�_�zS���TǦ����w�>��?�������n��U仆�V���e�����0���$�C�d���rP �m�׈e�Xm�Vu� �L��.�bֹ��� �[Դaզ���*��\y�8�Է:�Ez\�0�Kq�C b��̘��cө���Q��=0Y��s�N��S.��� 3.���O�o:���#���v7�[#߫ ��5�܎�L���Er4���9n��COWlG�^��0k�%<���ZB���aB_���������'=��{i�v�l�$�uC���mƎҝ{�c㱼�y]���W�i ��ߧc��m�H� m�"�"�����;Y�ߝ�Z�Ǔ�����:S#��|}�y�,/k�Ld� TA�(�AI$+I3��;Y*���Z��}|��ӧO��d�v��..#:n��f>�>���ȶI�TX��� 8��y����"d�R�|�)0���=���n4��6ⲑ�+��r<�O�܂~zh�z����7ܓ�HH�Ga롏���nCo�>������a ���~]���R���̲c?�6(�q�;5%� |�uj�~z8R =X��I�V=�|{v�Gj\gc��q����z�؋%M�ߍ����1y��#��@f^���^�>N��� ��#x#۹��6�Y~�?�dfPO��{��P�4��V��u1E1J �*|���%�� �JN��`eWu�zk M6���q t[�� ��g�G���v��WIG��u_ft����5�j�"�Y�:T��ɐ���*�;� e5���4����q$C��2d�}���� _S�L#m�Yp��O�.�C�;��c����Hi#֩%+) �Ӎ��ƲV���SYź��g |���tj��3�8���r|���V��1#;.SQ�A[���S������#���`n�+���$��$ I �P\[�@�s��(�ED�z���P��])8�G#��0B��[ى��X�II�q<��9�~[Z멜�Z�⊔IWU&A>�P~�#��dp<�?����7���c��'~���5 ��+$���lx@�M�dm��n<=e�dyX��?{�|Aef ,|n3�<~z�ƃ�uۧ�����P��Y,�ӥQ�*g�#먙R�\���;T��i,��[9Qi歉����c>]9�� ��"�c��P�� �Md?٥��If�ت�u��k��/����F��9�c*9��Ǎ:�ØF���z�n*�@|I�ށ9����N3{'��[�'ͬ�Ҳ4��#}��!�V� Fu��,�,mTIk���v C�7v���B�6k�T9��1�*l� '~��ƞF��lU��'�M ����][ΩũJ_�{�i�I�n��$�� �L�� j��O�dx�����kza۪��#�E��Cl����x˘�o�����V���ɞ�ljr��)�/,�߬h�L��#��^��L�ф�,íMƁe�̩�NB�L�����iL����q�}��(��q��6IçJ$�W�E$��:������=#����(�K�B����zђ <��K(�N�۫K�w��^O{!����) �H���>x�������lx�?>Պ�+�>�W���,Ly!_�D���Ō�l���Q�!�[ �S����J��1��Ɛ�Y}��b,+�Lo�x�ɓ)����=�y�oh�@�꥟/��I��ѭ=��P�y9��� �ۍYӘ�e+�p�Jnϱ?V\SO%�(�t� ���=?MR�[Ș�����d�/ ��n�l��B�7j� ��!�;ӥ�/�[-���A�>� dN�sLj ��,ɪv��=1c�.SQ�O3�U���ƀ�ܽ�E����������̻��9G�ϷD�7(�}��Ävӌ\� y�_0[w ���<΍>����a_��[0+�L��F.�޺��f�>oN�T����q;���y\��bՃ��y�jH�<|q-eɏ�_?_9+P���Hp$�����[ux�K w�Mw��N�ی'$Y2�=��q���KB��P��~�� ����Yul:�[<����F1�2�O���5=d����]Y�sw:���Ϯ���E��j,_Q��X��z`H1,#II ��d�wr��P˂@�ZJV����y$�\y�{}��^~���[:N����ߌ�U�������O��d�����ؾe��${p>G��3c���Ė�lʌ�� ת��[��`ϱ�-W����dg�I��ig2��� ��}s ��ؤ(%#sS@���~���3�X�nRG�~\jc3�v��ӍL��M[JB�T��s3}��j�Nʖ��W����;7� �ç?=X�F=-�=����q�ߚ���#���='�c��7���ڑW�I(O+=:uxq�������������e2�zi+�kuG�R��������0�&e�n���iT^J����~\jy���p'dtG��s����O��3����9* �b#Ɋ�� p������[Bws�T�>d4�ۧs���nv�n���U���_�~,�v����ƜJ1��s�� �QIz�� )�(lv8M���U=�;����56��G���s#�K���MP�=��LvyGd��}�VwWBF�'�à �?MH�U�g2�� ����!�p�7Q��j��ڴ����=��j�u��� Jn�A s���uM������e��Ɔ�Ҕ�!) '��8Ϣ�ٔ� �ޝ(��Vp���צ֖d=�IC�J�Ǡ{q������kԭ�߸���i��@K����u�|�p=..�*+����x�����z[Aqġ#s2a�Ɗ���RR�)*HRsi�~�a &f��M��P����-K�L@��Z��Xy�'x�{}��Zm+���:�)�) IJ�-i�u���� ���ܒH��'� L(7�y�GӜq���� j��� 6ߌg1�g�o���,kر���tY�?W,���p���e���f�OQS��!K�۟cҒA�|ս�j�>��=⬒��˧L[�� �߿2JaB~R��u�:��Q�] �0H~���]�7��Ƽ�I���( }��cq '�ήET���q�?f�ab���ӥvr� �)o��-Q��_'����ᴎo��K������;��V���o��%���~OK ����*��b�f:���-ťIR��`B�5!RB@���ï�� �u �̯e\�_U�_������� g�ES��3������� QT��a�� ��x����U<~�c?�*�#]�MW,[8O�a�x��]�1bC|踤�P��lw5V%�)�{t�<��d��5���0i�XSU��m:��Z�┵�i�"��1�^B�-��P�hJ��&)O��*�D��c�W��vM��)����}���P��ܗ-q����\mmζZ-l@�}��a��E�6��F�@��&Sg@���ݚ�M����� ȹ 4����#p�\H����dYDo�H���"��\��..R�B�H�z_�/5˘����6��KhJR��P�mƶi�m���3� ,#c�co��q�a)*P t����R�m�k�7x�D�E�\Y�閣_X�<���~�)���c[[�BP����6�Yq���S��0����%_����;��Àv�~�| VS؇ ��'O0��F0��\���U�-�d@�����7�SJ*z��3n��y��P����O��������� m�~�P�3|Y��ʉr#�C�<�G~�.,! ���bqx���h~0=��!ǫ�jy����l� O,�[B��~��|9��ٱ����Xly�#�i�B��g%�S��������tˋ���e���ې��\[d�t)��.+u�|1 ������#�~Oj����hS�%��i.�~X���I�H�m��0n���c�1uE�q��cF�RF�o���7� �O�ꮧ� ���ۛ{��ʛi5�rw?׌#Qn�TW��~?y$��m\�\o����%W� ?=>S�N@�� �Ʈ���R����N�)�r"C�:��:����� �����#��qb��Y�. �6[��2K����2u�Ǧ�HYR��Q�MV��� �G�$��Q+.>�����nNH��q�^��� ����q��mM��V��D�+�-�#*�U�̒ ���p욳��u:�������IB���m� ��PV@O���r[b= �� ��1U�E��_Nm�yKbN�O���U�}�the�`�|6֮P>�\2�P�V���I�D�i�P�O;�9�r�mAHG�W�S]��J*�_�G��+kP�2����Ka�Z���H�'K�x�W�MZ%�O�YD�Rc+o��?�q��Ghm��d�S�oh�\�D�|:W������UA�Qc yT�q� �����~^�H��/��#p�CZ���T�I�1�ӏT����4��"�ČZ�����}��`w�#�*,ʹ�� ��0�i��課�Om�*�da��^gJ݅{���l�e9uF#T�ֲ��̲�ٞC"�q���ߍ ոޑ�o#�XZTp����@ o�8��(jd��xw�]�,f���`~� |,s��^����f�1���t��|��m�򸄭/ctr��5s��7�9Q�4�H1꠲BB@ l9@���C�����+�wp�xu�£Yc�9��?`@#�o�mH�s2��)�=��2�.�l����jg�9$�Y�S�%*L������R�Y������7Z���,*=�䷘$�������arm�o�ϰ���UW.|�r�uf����IGw�t����Zwo��~5 ��YյhO+=8fF�)�W�7�L9lM�̘·Y���֘YLf�큹�pRF���99.A �"wz��=E\Z���'a� 2��Ǚ�#;�'}�G���*��l��^"q��+2FQ� hj��kŦ��${���ޮ-�T�٭cf�|�3#~�RJ����t��$b�(R��(����r���dx� >U b�&9,>���%E\� Ά�e�$��'�q't��*�א���ެ�b��-|d���SB�O�O��$�R+�H�)�܎�K��1m`;�J�2�Y~9��O�g8=vqD`K[�F)k�[���1m޼c��n���]s�k�z$@��)!I �x՝"v��9=�ZA=`Ɠi �:�E��)` 7��vI��}d�YI�_ �o�:ob���o ���3Q��&D&�2=�� �Ά��;>�h����y.*ⅥS������Ӭ�+q&����j|UƧ��� �}���J0��WW< ۋS�)jQR�j���Ư��rN)�Gű�4Ѷ(�S)Ǣ�8��i��W52���No˓� ۍ%�5brOn�L�;�n��\G����=�^U�dI���8$�&���h��'���+�(������cȁ߫k�l��S^���cƗjԌE�ꭔ��gF���Ȓ��@���}O���*;e�v�WV���YJ\�]X'5��ղ�k�F��b 6R�o՜m��i N�i���� >J����?��lPm�U��}>_Z&�KK��q�r��I�D�Չ~�q�3fL�:S�e>���E���-G���{L�6p�e,8��������QI��h��a�Xa��U�A'���ʂ���s�+טIjP�-��y�8ۈZ?J$��W�P� ��R�s�]��|�l(�ԓ��sƊi��o(��S0 ��Y� 8�T97.�����WiL��c�~�dxc�E|�2!�X�K�Ƙਫ਼�$((�6�~|d9u+�qd�^3�89��Y�6L�.I�����?���iI�q���9�)O/뚅����O���X��X�V��ZF[�یgQ�L��K1���RҖr@v�#��X�l��F���Нy�S�8�7�kF!A��sM���^rkp�jP�DyS$N���q�� nxҍ!U�f�!eh�i�2�m ���`�Y�I�9r�6� �TF���C}/�y�^���Η���5d�'��9A-��J��>{�_l+�`��A���[�'��յ�ϛ#w:݅�%��X�}�&�PSt�Q�"�-��\縵�/����$Ɨh�Xb�*�y��BS����;W�ջ_mc�����vt?2}1�;qS�d�d~u:2k5�2�R�~�z+|HE!)�Ǟl��7`��0�<�,�2*���Hl-��x�^����'_TV�gZA�'j� ^�2Ϊ��N7t�����?w�� �x1��f��Iz�C-Ȗ��K�^q�;���-W�DvT�7��8�Z�������� hK�(P:��Q- �8�n�Z���܃e貾�<�1�YT<�,�����"�6{ / �?�͟��|1�:�#g��W�>$����d��J��d�B�� =��jf[��%rE^��il:��B���x���Sּ�1հ��,�=��*�7 fcG��#q� �eh?��2�7�����,�!7x��6�n�LC�4x��},Geǝ�tC.��vS �F�43��zz\��;QYC,6����~;RYS/6���|2���5���v��T��i����������mlv��������&� �nRh^ejR�LG�f���? �ۉҬܦƩ��|��Ȱ����>3����!v��i�ʯ�>�v��オ�X3e���_1z�Kȗ\<������!�8���V��]��?b�k41�Re��T�q��mz��TiOʦ�Z��Xq���L������q"+���2ۨ��8}�&N7XU7Ap�d�X��~�׿��&4e�o�F��� �H�� ��O���č�c�� 懴�6���͉��+)��v;j��ݷ�� �UV�� i��� j���Y9GdÒJ1��詞�����V?h��l�� ��l�cGs�ځ�������y�Ac���� �\V3�? �� ܙg�>qH�S,�E�W�[�㺨�uch�⍸�O�}���a��>�q�6�n6� ���N6�q�� ���� N    ! 1AQaq�0@����"2BRb�#Pr���3C`��Scst���$4D���%Td��  ? � ��N����a��3��m���C���w��������xA�m�q�m��� m������$����4n淿t'��C"w��zU=D�\R+w�p+Y�T�&�պ@��ƃ��3ޯ?�Aﶂ��aŘ���@-�����Q�=���9D��ռ�ѻ@��M�V��P��܅�G5�f�Y<�u=,EC)�<�Fy'�"�&�չ�X~f��l�KԆV��?�� �W�N����=(� �;���{�r����ٌ�Y���h{�١������jW����P���Tc�����X�K�r��}���w�R��%��?���E��m�� �Y�q|����\lEE4� ��r���}�lsI�Y������f�$�=�d�yO����p�����yBj8jU�o�/�S��?�U��*������ˍ�0����� �u�q�m [�?f����a�� )Q�>����6#������� ?����0UQ����,IX���(6ڵ[�DI�MNލ�c&���υ�j\��X�R|,4��� j������T�hA�e��^���d���b<����n�� �즇�=!���3�^�`j�h�ȓr��jẕ�c�,ٞX����-����a�ﶔ���#�$��]w�O��Ӫ�1y%��L�Y<�wg#�ǝ�̗`�x�xa�t�w��»1���o7o5��>�m뭛C���Uƃߜ}�C���y1Xνm�F8�jI���]����H���ۺиE@I�i;r�8ӭ���� V�F�Շ| ��&?�3|x�B�MuS�Ge�=Ӕ�#BE5G�� ���Y!z��_e��q�р/W>|-�Ci߇�t�1ޯќd�R3�u��g�=0 5��[?�#͏��q�cf���H��{ ?u�=?�?ǯ���}Z��z���hmΔ�BFTW�����<�q� (v� ��!��z���iW]*�J�V�z��gX֧A�q�&��/w���u�gYӘa���; �i=����g:��?2�dž6�ى�k�4�>�Pxs����}������G�9� �3 ���)gG�R<>r h�$��'nc�h�P��Bj��J�ҧH� -��N1���N��?��~��}-q!=��_2hc�M��l�vY%UE�@|�v����M2�.Y[|y�"Eï��K�ZF,�ɯ?,q�?v�M 80jx�"�;�9vk�����+ ֧�� �ȺU��?�%�vcV��mA�6��Qg^M��� �A}�3�nl� QRN�l8�kkn�'�����(��M�7m9و�q���%ޟ���*h$Zk"��$�9��: �?U8�Sl��,,|ɒ��xH(ѷ����Gn�/Q�4�P��G�%��Ա8�N��!� �&�7�;���eKM7�4��9R/%����l�c>�x;������>��C�:�����t��h?aKX�bhe�ᜋ^�$�Iհ �hr7%F$�E��Fd���t��5���+�(M6�t����Ü�UU|zW�=a�Ts�Tg������dqP�Q����b'�m���1{|Y����X�N��b �P~��F^F:����k6�"�j!�� �I�r�`��1&�-$�Bevk:y���#y w��I0��x��=D�4��tU���P�ZH��ڠ底taP��6����b>�xa� ���Q�#� WeF��ŮNj�p�J* mQ�N��� �*I�-*�ȩ�F�g�3 �5��V�ʊ�ɮ�a��5F���O@{���NX��?����H�]3��1�Ri_u��������ѕ�� ����0��� F��~��:60�p�͈�S��qX#a�5>���`�o&+�<2�D����: �������ڝ�$�nP���*)�N�|y�Ej�F�5ټ�e���ihy�Z �>���k�bH�a�v��h�-#���!�Po=@k̆IEN��@��}Ll?j�O������߭�ʞ���Q|A07x���wt!xf���I2?Z��<ץ�T���cU�j��]�� 陎Ltl �}5�ϓ��$�,��O�mˊ�;�@O��jE��j(�ا,��LX���LO���Ц�90�O �.����a��nA���7������j4 ��W��_ٓ���zW�jcB������y՗+EM�)d���N�g6�y1_x��p�$Lv :��9�"z��p���ʙ$��^��JԼ*�ϭ����o���=x�Lj�6�J��u82�A�H�3$�ٕ@�=Vv�]�'�qEz�;I˼��)��=��ɯ���x �/�W(V���p�����$ �m�������u�����񶤑Oqˎ�T����r��㠚x�sr�GC��byp�G��1ߠ�w e�8�$⿄����/�M{*}��W�]˷.�CK\�ުx���/$�WP w���r� |i���&�}�{�X� �>��$-��l���?-z���g����lΆ���(F���h�vS*���b���߲ڡn,|)mrH[���a�3�ר�[1��3o_�U�3�TC�$��(�=�)0�kgP���� ��u�^=��4 �WYCҸ:��vQ�ר�X�à��tk�m,�t*��^�,�}D*� �"(�I��9R����>`�`��[~Q]�#af��i6l��8���6�:,s�s�N6�j"�A4���IuQ��6E,�GnH��zS�HO�uk�5$�I�4��ؤ�Q9�@��C����wp �BGv[]�u�Ov��� 0I4���\��y�����Q�Ѹ��~>Z��8�T��a��q�ޣ;z��a���/��S��I:�ܫ_�|������>=Z����8:�S��U�I�J��"IY���8%b8���H��:�QO�6�;7�I�S��J��ҌAά3��>c���E+&jf$eC+�z�;��V����� �r���ʺ������my�e���aQ�f&��6�ND ��.:��NT�vm�<- u���ǝ\MvZY�N�NT��-A�>jr!S��n�O 1�3�Ns�%�3D@���`������ܟ 1�^c<���� �a�ɽ�̲�Xë#�w�|y�cW�=�9I*H8�p�^(4���՗�k��arOcW�tO�\�ƍR��8����'�K���I�Q�����?5�>[�}��yU�ײ -h��=��% q�ThG�2�)���"ו3]�!kB��*p�FDl�A���,�eEi�H�f�Ps�����5�H:�Փ~�H�0Dت�D�I����h�F3�������c��2���E��9�H��5�zԑ�ʚ�i�X�=:m�xg�hd(�v����׊�9iS��O��d@0ڽ���:�p�5�h-��t�&���X�q�ӕ,��ie�|���7A�2���O%P��E��htj��Y1��w�Ѓ!����  ���� ࢽ��My�7�\�a�@�ţ�J �4�Ȼ�F�@o�̒?4�wx��)��]�P��~�����u�����5�����7X ��9��^ܩ�U;Iꭆ 5 �������eK2�7(�{|��Y׎ �V��\"���Z�1� Z�����}��(�Ǝ"�1S���_�vE30>���p;� ΝD��%x�W�?W?v����o�^V�i�d��r[��/&>�~`�9Wh��y�;���R�� � ;;ɮT��?����r$�g1�K����A��C��c��K��l:�'��3 c�ﳯ*"t8�~l��)���m��+U,z��`( �>yJ�?����h>��]��v��ЍG*�{`��;y]��I�T� ;c��NU�fo¾h���/$���|NS���1�S�"�H��V���T���4��uhǜ�]�v;���5�͠x��'C\�SBpl���h}�N����� A�Bx���%��ޭ�l��/����T��w�ʽ]D�=����K���ž�r㻠l4�S�O?=�k �M:� ��c�C�a�#ha���)�ѐxc�s���gP�iG�� {+���x���Q���I= �� z��ԫ+ �8"�k�ñ�j=|����c ��y��CF��/ ��*9ж�h{ �?4�o� ��k�m�Q�N�x��;�Y��4膚�a�w?�6�> e]�����Q�r�:����g�,i"�����ԩA� *M�<�G��b�if��l^M��5� �Ҩ�{����6J��ZJ�����P�*�����Y���ݛu�_4�9�I8�7���������,^ToR���m4�H��?�N�S�ѕw��/S��甍�@�9H�S�T��t�ƻ���ʒU��*{Xs�@����f��� ��֒Li�K{H�w^���������Ϥm�tq���s� ���ք��f:��o~s��g�r��ט� �S�ѱC�e]�x���a��) ���(b-$(�j>�7q�B?ӕ�F��hV25r[7 Y� }L�R��}����*sg+��x�r�2�U=�*'WS��ZDW]�WǞ�<��叓���{�$�9Ou4��y�90-�1�'*D`�c�^o?(�9��u���ݐ��'PI&� f�Jݮ�������:wS����jfP1F:X �H�9dԯ�� �˝[�_54 �}*;@�ܨ�� ð�yn�T���?�ןd�#���4rG�ͨ��H�1�|-#���Mr�S3��G�3�����)�.᧏3v�z֑��r����$G"�`j �1t��x0<Ɔ�Wh6�y�6��,œ�Ga��gA����y��b��)� �h�D��ß�_�m��ü �gG;��e�v��ݝ�nQ� ��C����-�*��o���y�a��M��I�>�<���]obD��"�:���G�A��-\%LT�8���c�)��+y76���o�Q�#*{�(F�⽕�y����=���rW�\p���۩�c���A���^e6��K������ʐ�cVf5$�'->���ՉN"���F�"�UQ@�f��Gb~��#�&�M=��8�ט�JNu9��D��[̤�s�o�~��� ��� G��9T�tW^g5y$b��Y'��س�Ǵ�=��U-2 #�MC�t(�i� �lj�@Q 5�̣i�*�O����s�x�K�f��}\��M{E�V�{�υ��Ƈ�����);�H����I��fe�Lȣr�2��>��W� I�Ȃ6������i��k�� �5�YOxȺ����>��Y�f5'��|��H+��98pj�n�.O�y�������jY��~��i�w'������l�;�s�2��Y��:'lg�ꥴ)o#'Sa�a�K��Z� �m��}�`169�n���"���x��I ��*+� }F<��cГ���F�P�������ֹ*�PqX�x۩��,� ��N�� �4<-����%����:��7����W���u�`����� $�?�I��&����o��o��`v�>��P��"��l���4��5'�Z�gE���8���?��[�X�7(��.Q�-��*���ތL@̲����v��.5���[��=�t\+�CNܛ��,g�SQnH����}*F�G16���&:�t��4ُ"A��̣��$�b �|����#rs��a�����T�� ]�<�j��B S�('$�ɻ� �wP;�/�n��?�ݜ��x�F��yUn�~mL*-�������Xf�wd^�a�}��f�,=t�׵i�.2/wpN�Ep8�OР���•��R�FJ� 55TZ��T �ɭ�<��]��/�0�r�@�f��V��V����Nz�G��^���7hZi����k��3�,kN�e|�vg�1{9]_i��X5y7� 8e]�U����'�-2,���e"����]ot�I��Y_��n�(JҼ��1�O ]bXc���Nu�No��pS���Q_���_�?i�~�x h5d'�(qw52] ��'ޤ�q��o1�R!���`ywy�A4u���h<קy���\[~�4�\ X�Wt/� 6�����n�F�a8��f���z �3$�t(���q��q�x��^�XWeN'p<-v�!�{�(>ӽDP7��ո0�y)�e$ٕv�Ih'Q�EA�m*�H��RI��=:��� ���4牢) �%_iN�ݧ�l]� �Nt���G��H�L��� ɱ�g<���1V�,�J~�ٹ�"K��Q�� 9�HS�9�?@��k����r�;we݁�]I�!{ �@�G�[�"��`���J:�n]�{�cA�E����V��ʆ���#��U9�6����j�#Y�m\��q�e4h�B�7��C�������d<�?J����1g:ٳ���=Y���D�p�ц� ׈ǔ��1�]26؜oS�'��9�V�FVu�P�h�9�xc�oq�X��p�o�5��Ա5$�9W�V(�[Ak�aY錎qf;�'�[�|���b�6�Ck��)��#a#a˙��8���=äh�4��2��C��4tm^ �n'c� ��]GQ$[Wҿ��i���vN�{Fu ��1�gx��1┷���N�m��{j-,��x�� Ūm�ЧS�[�s���Gna���䑴�� x�p 8<������97�Q���ϴ�v�aϚG��Rt�Һ׈�f^\r��WH�JU�7Z���y)�vg=����n��4�_)y��D'y�6�]�c�5̪ �\� �PF�k����&�c;��cq�$~T�7j ���nç]�<�g ":�to�t}�159�<�/�8������m�b�K#g'I'.W����� 6��I/��>v��\�MN��g���m�A�yQL�4u�Lj�j9��#44�t��l^�}L����n��R��!��t��±]��r��h6ٍ>�yҏ�N��fU�� ���� Fm@�8}�/u��jb9������he:A�y�ծw��GpΧh�5����l}�3p468��)U��d��c����;Us/�֔�YX�1�O2��uq�s��`hwg�r~�{ R��mhN��؎*q 42�*th��>�#���E����#��Hv�O����q�}����� 6�e��\�,Wk�#���X��b>��p}�դ��3���T5��†��6��[��@ �P�y*n��|'f�֧>�lư΂�̺����SU�'*�q�p�_S�����M�� '��c�6��� ��m�� ySʨ;M��r���Ƌ�m�Kxo,���Gm�P��A�G�:��i��w�9�}M(�^�V��$ǒ�ѽ�9���|���� �a����J�SQ�a���r�B;����}���ٻ֢�2�%U���c�#�g���N�a�ݕ�'�v�[�OY'��3L�3�;,p�]@�S��{ls��X�'���c�jw� k'a�.��}�}&�� �dP�*�bK=ɍ!����;3n�gΊU�ߴmt�'*{,=SzfD� A��ko~�G�aoq�_mi}#�m�������P�Xhύ��� �mxǍ�΂���巿zf��Q���c���|kc�����?���W��Y�$���_Lv����l߶��c���`?����l�j�ݲˏ!V��6����U�Ђ(A���4y)H���p�Z_�x��>���e�� R��$�/�`^'3qˏ�-&Q�=?��CFVR �D�fV�9��{�8g�������n�h�(P"��6�[�D���< E�����~0<@�`�G�6����Hг�cc�� �c�K.5��D��d�B���`?�XQ��2��ٿyqo&+�1^� DW�0�ꊩ���G�#��Q�nL3��c���������/��x ��1�1 [y�x�პCW��C�c�UĨ80�m�e�4.{�m��u���I=��f�����0QRls9���f���������9���~f�����Ǩ��a�"@�8���ȁ�Q����#c�ic������G��$���G���r/$W�(��W���V�"��m�7�[m�A�m����bo��D� j����۳� l���^�k�h׽����� ��#� iXn�v��eT�k�a�^Y�4�BN�� ĕ�� 0    !01@Q"2AaPq3BR������ ? � ��@4�Q�����T3,���㺠�W�[=JK�Ϟ���2�r^7��vc�:�9 �E�ߴ�w�S#d���Ix��u��:��Hp��9E!�� V 2;73|F��9Y���*ʬ�F��D����u&���y؟��^EA��A��(ɩ���^��GV:ݜDy�`��Jr29ܾ�㝉��[���E;Fzx��YG��U�e�Y�C���� ����v-tx����I�sם�Ę�q��Eb�+P\ :>�i�C'�;�����k|z�رn�y]�#ǿb��Q��������w�����(�r|ӹs��[�D��2v-%��@;�8<a���[\o[ϧw��I!��*0�krs)�[�J9^��ʜ��p1)� "��/_>��o��<1����A�E�y^�C��`�x1'ܣn�p��s`l���fQ��):�l����b>�Me�jH^?�kl3(�z:���1ŠK&?Q�~�{�ٺ�h�y���/�[��V�|6��}�KbX����mn[-��7�5q�94�������dm���c^���h� X��5��<�eޘ>G���-�}�دB�ޟ� ��|�rt�M��V+�]�c?�-#ڛ��^ǂ}���Lkr���O��u�>�-D�ry� D?:ޞ�U��ǜ�7�V��?瓮�"�#���r��չģVR;�n���/_� ؉v�ݶe5d�b9��/O��009�G���5n�W����JpA�*�r9�>�1��.[t���s�F���nQ� V 77R�]�ɫ8����_0<՜�IF�u(v��4��F�k�3��E)��N:��yڮe��P�`�1}�$WS��J�SQ�N�j �ٺ��޵�#l���ј(�5=��5�lǏmoW�v-�1����v,W�mn��߀$x�<����v�j(����c]��@#��1������Ǔ���o'��u+����;G�#�޸��v-lη��/(`i⣍Pm^� ��ԯ̾9Z��F��������n��1��� ��]�[��)�'������ :�֪�W��FC����� �B9،!?���]��V��A�Վ�M��b�w��G F>_DȬ0¤�#�QR�[V��kz���m�w�"��9ZG�7'[��=�Q����j8R?�zf�\a�=��O�U����*oB�A�|G���2�54 �p��.w7� �� ��&������ξxGHp� B%��$g�����t�Џ򤵍z���HN�u�Я�-�'4��0�� ;_�� 3     !01"@AQa2Pq#3BR������ ? � �ʩca��en��^��8���<�u#��m*08r��y�N"�<�Ѳ0��@\�p��� �����Kv�D��J8�Fҽ� �f�Y��-m�ybX�NP����}�!*8t(�OqѢ��Q�wW�K��ZD��Δ^e��!� ��B�K��p~�����e*l}z#9ң�k���q#�Ft�o��S�R����-�w�!�S���Ӥß|M�l޶V��!eˈ�8Y���c�ЮM2��tk���� ������J�fS����Ö*i/2�����n]�k�\���|4yX�8��U�P.���Ы[���l��@"�t�<������5�lF���vU�����W��W��;�b�cД^6[#7@vU�xgZv��F�6��Q,K�v��� �+Ъ��n��Ǣ��Ft���8��0��c�@�!�Zq s�v�t�;#](B��-�nῃ~���3g������5�J�%���O������n�kB�ĺ�.r��+���#�N$?�q�/�s�6��p��a����a��J/��M�8��6�ܰ"�*������ɗud"\w���aT(����[��F��U՛����RT�b���n�*��6���O��SJ�.�ij<�v�MT��R\c��5l�sZB>F��<7�;EA��{��E���Ö��1U/�#��d1�a�n.1ě����0�ʾR�h��|�R��Ao�3�m3 ��%�� ���28Q� ��y��φ���H�To�7�lW>����#i`�q���c����a��� �m,B�-j����݋�'mR1Ήt�>��V��p���s�0IbI�C.���1R�ea�����]H�6�������� ��4B>��o��](��$B���m�����a�!=� �?�B� K�Ǿ+�Ծ"�n���K��*��+��[T#�{ E�J�S����Q�����s�5�:�U�\wĐ�f�3����܆&�)��� �I���Ԇw��E T�lrTf6Q|R�h:��[K�� �z��c֧�G�C��%\��_�a �84��HcO�bi��ؖV��7H �)*ģK~Xhչ0��4?�0��� �E<���}3���#���u�?�� ��|g�S�6ꊤ�|�I#Hڛ� �ա��w�X��9��7���Ŀ%�SL��y6č��|�F�a 8���b� �$�sק�h���b9RAu7�˨p�Č�_\*w��묦��F ����4D~�f����|(�"m���NK��i�S�>�$d7SlA��/�²����SL��|6N�}���S�˯���g��]6��; �#�.��<���q'Q�1|KQ$�����񛩶"�$r�b:���N8�w@��8$�� �AjfG|~�9F ���Y��ʺ��Bwؒ������M:I岎�G��`s�YV5����6��A �b:�W���G�q%l�����F��H���7�������Fsv7� �k�� 403WebShell
403Webshell
Server IP : 127.0.0.1  /  Your IP : 10.100.1.254
Web Server : Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30
System : Windows NT WIZC-EXTRANET 10.0 build 19045 (Windows 10) AMD64
User : SYSTEM ( 0)
PHP Version : 8.0.30
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /Users/owner/AppData/Local/Microsoft/Edge/User Data/Default/Cache/Cache_Data/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /Users/owner/AppData/Local/Microsoft/Edge/User Data/Default/Cache/Cache_Data/f_000051
/* INIT */

var body = $('body');

var isProduct = body.find('[name="is_product"]').val();

var googleAnalyticsID = body.find('[name="google_analytics_id"]').val();

const isTestUser = parseInt(body.find('[name="is_test_user"]').val());

var currentPath;
var currentFile = body.find('[name="current_file"]').val();
var currentPage;
var currentType;
var currentID;
var currentAdditionalParameters;

/* PAGINATION VARS */
var parameterStatus;
var parameterSearch;
var parameterLimit;
var parameterPage;

var autoRefreshInterval;
var autoRefreshCount = 0;

var htmlTitle;

var browserHistory = [];

const urlParams = new URLSearchParams(window.location.search);

function init() {

	/* stop auto-refresh */
	stopAutoRefresh();

	// set auto refresh counter back to 0
	if (currentPage !== 'install') {
	autoRefreshCount = 0;
	}

	/* set environment variables */
	currentPath = window.location.pathname;
	currentPage = $('[name="current_page"]').val();
	currentType = $('[name="current_type"]').val();
	currentID = $('[name="current_id"]').val();
	htmlTitle = body.find('[name="html_title"]').val();
	currentAdditionalParameters = $('[name="current_additional_parameters"]').val();

	/* set page title */
	$('title').text(htmlTitle + ' - ZeroSSL');

	/* fix for iOS devices not finishing Pace.js loading - https://github.com/HubSpot/pace/issues/440 */
	(function ($) {
		if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
			Pace.stop();
		}
	}) (jQuery);

	// force a fake encryption key if url parameter is set
	if(window.location.href.indexOf('force_key=1') !== -1) {
		storeEncryptionKey('force_key');
	}

	/* if user has no encryption key in local storage, auto log out */
	if (!localStorage.getItem('encryption_key') || localStorage.getItem('encryption_key').length < 64) {
		logOut('encryption_key');
	}

	/* invalidate all private keys if local storage item present */
	if (localStorage.getItem('inv_pk') === 'true') {

		// perform invalidation
		invalidateAllPrivateKeys();

		// remove cookie afterwards
		localStorage.removeItem('inv_pk') ;

	}

	/* close mobile dropdown menu */
	body.find('.mobile_dropdown_open').removeClass('mobile_dropdown_open').hide();
	body.removeClass('overflow_hidden');

	/* handle Zendesk widget */
	handleZendeskWidget();

	/* page specific init */
	switch (currentPage) {

		case 'certificates':
			loadTable();
		break;

		case 'checkout':

			if (body.find('[name="checkout[paid_or_cancelled]"]').val() != 'true') {
			initStripe('elements_enabled');
			}

		break;

		case 'order':

			// process domain passed from signup
			if (body.find('[name="additional_parameter[domain_to_secure]"]').val()) {
			processDomainsToProtect(body.find('[name="wizard[order][domains][domain]"]'));
			}

			// if renewal, process all domains and pre-select plan
			if (body.find('[name="wizard[order][is_renewal]"]').val() === 'true') {
			processAllDomains();
			wizardPreselectPlan();
			}


		break;

		case 'install':

			// start auto-refresh
			if (body.find('[name="enable_auto_refresh"]').val() === 'true') {
			startAutoRefresh();
			}

		break;

	}

	initForge();

	// ZERO-178
	// Set default selected domain verification method on loading of Verify Domain page.
	// This domain verification method will then be propagated and displayed at the Finalize Domain verification step
	if (currentPage && currentPage === "verify") {
		updateVerificationSummary();
	}

	// ZERO-148
	// When user is inputting certificate name on "certificate/new", pressing enter key would reload page,
	// instead we want user to go to next step in the wizard.
	if (currentPage && currentPage === "order") {
		preventEnterKeyOnCertificateNameInput();
	}
}

function preventEnterKeyOnCertificateNameInput() {
	$('form[name="wizard[order][domains]"]').on("keypress", function(e) {
		const key = e.charCode || e.keyCode || 0;
		if (key == 13) {
			e.preventDefault();
			$(".next_step").first().trigger("click");
		}
	})
}

/* INITIAL PAGE LOAD */
$(document).ready(function() {
	"use strict";

	// prevent caching with ajax
	$.ajaxSetup({ cache: false });

	init();
	currentPath = window.location.pathname;

	browserHistory[0] = {
			indexNo: 0,
			pagePath: window.location.pathname,
			getFile: body.find('[name="current_file"]').val(),
			getPage: body.find('[name="current_page"]').val(),
			getType: body.find('[name="current_type"]').val(),
			getID: body.find('[name="current_id"]').val(),
			getAdditionalParameters: body.find('[name="current_additional_parameters"]').val(),
	};

	//console.log(JSON.stringify(browserHistory));

});

/* AJAX PAGE LOAD */
function goToPage(pagePath, getFile, getPage, getType, getID, isBackOrForward, generalInfoArray, additionalParams) {

	var URL;

    let acstat = parseInt(body.attr('data-acstat'));

    if(acstat === 3) {
        let blockedPages = ["dashboard","certificates","developer","protection"];

        for(let blockedIndex in blockedPages) {
            if(getPage.startsWith(blockedPages[blockedIndex])) {
                window.location.href = "/billing";
            }
        }
    }
	if (additionalParams) {
	    URL = '/pages/'+getFile+'.php?is_ajax=1&page='+getPage+'&type='+getType+'&id='+getID + additionalParams;
	} else {
	    URL = '/pages/'+getFile+'.php?is_ajax=1&page='+getPage+'&type='+getType+'&id='+getID;
	}

	// if target URL is not current URL
	if (pagePath !== window.location) {

		// rewrite URL in browser
		window.history.pushState({path:pagePath}, '', pagePath);

		// only save this page to browser history if it's not the back button AND if target page is not the last saved page
		if (isBackOrForward !== true && (browserHistory[browserHistory.length-1] !== undefined) && (browserHistory[browserHistory.length-1].pagePath !== pagePath)) {

			var indexNo = browserHistory.length;

			browserHistory[indexNo] = {
			indexNo: indexNo,
			pagePath: pagePath,
			getFile: getFile,
			getPage: getPage,
			getType: getType,
			getID: getID,
			getAdditionalParameters: additionalParams
			};

			/* refresh environment variables */
			currentFile = getFile;
			currentPath = pagePath;

		}

		//console.log(JSON.stringify(browserHistory));

	}

	$.ajax({
		type: 'GET',
		url: URL,
		dataType: "html",
		statusCode: {
    		205: function() {
        	window.location.href = '/login';
			return false;
    		}
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data) {

			// append page to main content
			$('main').html(data);

			// initialize
			init();

			// alert after page change
			if (generalInfoArray) {

				generalInfo(generalInfoArray[0], generalInfoArray[1], generalInfoArray[2], generalInfoArray[3]);

			}

			// scroll to top
			scrollToTop(0);

			// send GA event
			gtag('config', googleAnalyticsID, {
			  'page_path': pagePath
			});

			return false;

		}

	});

}


/* REFRESH CURRENT PAGE */
function reloadPage(generalInfoArray) {
	'use strict';
	goToPage(currentPath, currentFile, currentPage, currentType, currentID, true, generalInfoArray, currentAdditionalParameters);
}


body.on('click', '[data-ajax="true"]', function (event) {

	event.preventDefault();

	var pagePath = $(this).attr('href');

    // Check "open in new window/tab" key modifiers
    if (event.shiftKey || event.ctrlKey || event.metaKey) {
	window.open(pagePath, '_blank');
	return false;
	}

	var getFile = $(this).attr('data-ajax-get-file');
	var getPage = $(this).attr('data-ajax-get-page');
	var getType = $(this).attr('data-ajax-get-type');
	var getID = $(this).attr('data-ajax-get-id');

	var getAdditionalParams = $(this).attr('data-ajax-get-parameters') ? $(this).attr('data-ajax-get-parameters') : null;

	/* respect last page additional parameters for onpage back button */
	if ($(this).attr('data-ajax-is-onpage-back-button') && browserHistory.length > 1) {

		getAdditionalParams = browserHistory[browserHistory.length - 2].getAdditionalParameters;

		if (!pagePath) {
		pagePath = browserHistory[browserHistory.length - 2].pagePath;
		}

	}

	goToPage(pagePath, getFile, getPage, getType, getID, false, null, getAdditionalParams);

});



/* HANDLE BACK BUTTON */
$(window).bind('popstate', function() {
	"use strict";

	var indexNo = browserHistory.length;
	var indexNoBefore = indexNo - 2;

	if (indexNo > 1) {

		var pagePath = browserHistory[indexNoBefore].pagePath;
		var getFile = browserHistory[indexNoBefore].getFile;
		var getPage = browserHistory[indexNoBefore].getPage;
		var getType = browserHistory[indexNoBefore].getType;
		var getID = browserHistory[indexNoBefore].getID;
		var getAdditionalParams = browserHistory[indexNoBefore].getAdditionalParameters;

		//console.log(getAdditionalParams);

		goToPage(pagePath, getFile, getPage, getType, getID, true, null, getAdditionalParams);
		browserHistory = browserHistory.slice(0, -1);

	}

});


/* CHANGE PASSWORD SWITCHER */
body.on('click', '[data-action="change_password"]', function (event) {

	event.preventDefault();

	var button = $(this);
	var form = $(this).closest('form');

	if (!button.attr('data-action-confirmed') && !form.hasClass('changing_password')) {

		openPopup('confirm_change_password');

		body.on('submit', 'form[name="confirm_change_password"]', function(event) {

			event.preventDefault();

			// add confirmation tag for a second, re-submit action, then remove confirmation tag
			button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

			// open change password form
			form.addClass('changing_password');

			closePopup();

		});

		return false;

	}

	form.toggleClass('changing_password');

	form.find('[name="account[details][current_password]"]').val('');
	form.find('[name="account[details][new_password]"]').val('');
	form.find('[name="account[details][new_password_repeat]"]').val('');


});

body.on('keyup', '#change_password_understand', function(e) {
    e.preventDefault();
    if($(this).val() === "UNDERSTOOD") {
        $('#confirm_change_password_submit').removeAttr('disabled');
    }
});

/* AJAX - SAVE ACCOUNT DETAILS */
body.on('submit', 'form[name="account[details]"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this).find('button[type="submit"]');

	var error = false;
	var errors = 0;

	var userChangePassword = false;

	body.find('[data-required="true"]:visible').each(function() {

		if (!$(this).val()) {
		errors ++;
		$(this).addClass('error');
		} else {
		$(this).removeClass('error');
		}

	});

	if (errors > 0) {
	error = true;
	}

	// check password strength, custom error
	if (body.find('[name="account[details][new_password]"]').is(':visible')) {

		userChangePassword = true;

		if (!passwordStrength(body.find('[name="account[details][new_password]"]').val())) {

			body.find('[name="account[details][new_password]"]').addClass('error');
			generalInfo('show', 'error', 'New password must contain: 8 characters or more, including lowercase, uppercase characters and a number.');
			return false;

		} else {
			body.find('[name="account[details][new_password]"]').removeClass('error');
		}

	}

	if (error === true) {
	generalInfo('show', 'error', 'There were errors. Please fill all required fields and try again.');
	return false;
	} else {
	generalInfo('hide');
	}

	button.addClass('loading');

	var passwordValue = body.find('[name="account[details][new_password]"]').val();

	var	postData = {
		email_address: body.find('[name="account[details][email]"]').val(),
		current_password: generateSHA256(body.find('[name="account[details][current_password]"]').val()),
		new_password: generateSHA256(body.find('[name="account[details][new_password]"]').val()),
		new_password_again: generateSHA256(body.find('[name="account[details][new_password_repeat]"]').val()),
		first_name: body.find('[name="account[details][first_name]"]').val(),
		last_name: body.find('[name="account[details][last_name]"]').val(),
		address: body.find('[name="account[details][address]"]').val(),
		post_code: body.find('[name="account[details][postal_code]"]').val(),
		state: body.find('[name="account[details][state]"]').val(),
		city: body.find('[name="account[details][city]"]').val(),
		country_code: body.find('[name="account[details][country_code]"]').val(),
		company_name: body.find('[name="account[details][company_name]"]').val(),
		website_url: body.find('[name="account[details][website_url]"]').val(),
		tax_id: body.find('[name="account[details][tax_id]"]').val(),
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=edit_account&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				if (userChangePassword === true) {

					// store new encryption key
					storeEncryptionKey(passwordValue);

					// invalidate all private keys
					invalidateAllPrivateKeys();

				}

				button.removeClass('loading');

				reloadPage(['show', 'success', 'Your account details have been updated.']);
				return false;

			}  else {

				button.removeClass('loading');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});


/* AJAX - SAVE ACCOUNT DETAILS */
body.on('submit', 'form[id="notification"]', function(e) {
    "use strict";
    e.preventDefault();

    let button = $(this).find('button[type="submit"]');

    button.addClass('loading');
    let	postData = {
        notificationOptOutStatus: body.find('[name="notification[status]"]:checked').val(),
        notificationOptOutExpiration: body.find('[name="notification[expiration]"]:checked').val(),
        notificationAcmeOptOutStatus: body.find('[name="notification[status_acme]"]:checked').val(),
        notificationAcmeOptInExpiration: body.find('[name="notification[expiration_acme]"]:checked').val(),
    };

    let postDataJSON = JSON.stringify(postData);

    $.ajax({
        type: "POST",
        url: '/ajax/advanced_ajax_handler.php?type=upsert_user_settings&_cpt=' + getCookie('_cpt'),
        data: ({ postArray: postDataJSON }),
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            generalInfo('show', 'error', translateError('Error updating account details. Maybe your internet connection is gone? Please try again later.'));
            return false;
        },
        success: function(data){
            if (data.success === 1) {
                button.removeClass('loading');
                reloadPage(['show', 'success', 'Your user settings have been updated.']);
                return false;
            }  else {
                button.removeClass('loading');
                generalInfo('show', 'error', translateError(data.message));
                return false;
            }
        }
    });
});

body.on('click', '[class="protection_enable"]', function(e) {
    "use strict";
    e.preventDefault();

    button.addClass('loading');
    let	postData = {
        notificationOptOutStatus: body.find('[name="notification[status]"]:checked').val(),
        notificationOptOutExpiration: body.find('[name="notification[expiration]"]:checked').val(),
        notificationAcmeOptOutStatus: body.find('[name="notification[status_acme]"]:checked').val(),
        notificationAcmeOptInExpiration: body.find('[name="notification[expiration_acme]"]:checked').val(),
    };

    let postDataJSON = JSON.stringify(postData);

    $.ajax({
        type: "POST",
        url: '/ajax/advanced_ajax_handler.php?type=upsert_user_settings&_cpt=' + getCookie('_cpt'),
        data: ({ postArray: postDataJSON }),
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            generalInfo('show', 'error', translateError('Error updating account details. Maybe your internet connection is gone? Please try again later.'));
            return false;
        },
        success: function(data){
            if (data.success === 1) {
                button.removeClass('loading');
                reloadPage(['show', 'success', 'Your user settings have been updated.']);
                return false;
            }  else {
                button.removeClass('loading');
                generalInfo('show', 'error', translateError(data.message));
                return false;
            }
        }
    });
});


/* POPUP */
function openPopup(actionID, customObject, callback) {

	var fileToLoad;

	var popupContent;

	// close all dropdown menus
	closeAllDropdownMenus();

	// disable scrolling
	body.addClass('popup_open');

	// init popup
	body.find('.popup_backdrop').show();
	body.find('.popup').show();

	scrollToTop(0);

	switch (actionID) {

		// placeholder for custom popups
		default:
		fileToLoad = actionID;
		break;

	}

	$.ajax({
		type: "POST",
		url: '/popups/'+fileToLoad+'.php?action_id='+actionID,
		data: ({ postArray: customObject }),
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			// add content to popup window
			body.find('.popup .window').html(data);

			// remove loading and show content
			body.find('.popup .window').removeClass('loading');
			body.find('.popup .window .content').fadeIn(100);

			if (actionID === 'add_payment_method') {
				stripeGetSetupIntentSecret();
			}

			if (actionID === 'checkout_via_popup') {
				initStripe('elements_enabled');
			}

			if (currentPage && currentPage === "certificates") {
				// ZERO-33 only allow users to click on revocation certificate button, when they clicked confirmation checkbox
				// ZERO-234 and if users specified revocation reason
				let userDidSpecifyRevokationReason = false;
				let userClickedRevocationTerms = false;

				$("#revocation_reason").change(() => {
					userDidSpecifyRevokationReason = true;
					checkIfUserIsAllowedToRevocate();
				})

				$("#revocation-confirmation-checkbox").change(function () {
					this.checked ? userClickedRevocationTerms = true : userClickedRevocationTerms = false;
					checkIfUserIsAllowedToRevocate();
				});

				function checkIfUserIsAllowedToRevocate() {
					$("#confirm-revoke-certificate-btn").attr("disabled", true);

					if (userDidSpecifyRevokationReason && userClickedRevocationTerms) {
						$("#confirm-revoke-certificate-btn").attr("disabled", false);
					}
				}
			}

			if (callback) {
				callback();
			}

			return false;
		}

	});

}


body.on('click', '[data-action="popup"]', function () {

	var actionID = $(this).attr('data-action-id');

	openPopup(actionID);

});


function closePopup() {

	body.removeClass('popup_open');

	body.find('.popup .content').remove();
	body.find('.popup .window').addClass('loading');

	body.find('.popup_backdrop').hide();
	body.find('.popup').hide();

}

body.on('click', '[data-action="close_popup"]', function() {

	closePopup();

});


/* DELETE ACCOUNT - TYPE KEYUP */
body.on('keyup', '[name="account[delete][type_delete]"]', function() {

	if ($(this).val() == 'DELETE') {
	body.find('button[type="submit"][form="account[delete]"]').addClass('enabled');
	} else {
	body.find('button[type="submit"][form="account[delete]"]').removeClass('enabled');
	}

});


/* AJAX - DELETE ACCOUNT */
body.on('submit', 'form[name="account[delete]"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this).find('button[type="submit"]');
	var typeDelete = $(this).find('[name="account[delete][type_delete]"]');

	if (typeDelete.val() === 'DELETE') {
	generalInfo('hide');
	} else {
	generalInfo('show', 'error', 'An error occurred. Please try again.');
	return false;
	}

	button.addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=delete_account&_cpt=' + getCookie('_cpt'),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				window.location.href = '/login/deleted';
				return false;

			}  else {

				button.removeClass('loading');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});


/* AJAX - LOG OUT */
function logOut(command) {

    let redirectURL = '/login/bye';

    if (command === 'encryption_key') {
	    redirectURL = 'login/session';
	}

	$.ajax({
		type: "POST",
		url: '/ajax/public_ajax_handler.php?type=sign_out',
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				window.location.href = redirectURL;
				return false;

			}  else {

				console.log(data.message);
				return false;

			}

		}

	});

}

body.on('click', '[data-action="logout"]', function(e) {
	"use strict";
	e.preventDefault();

	body.addClass('loading');
	body.addClass('logging_out');

	logOut();

});



/* AJAX - CHANGE PLAN */
body.on('click', '[data-action="change_plan"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this);

	var planID = $(this).attr('data-action-id');
	var actionType = $(this).attr('data-action-type');

	var	postData = {
		plan_id: planID,
		payment_frequency: body.find('[name="user[payment_frequency]"]').val(),
	};

	var postDataJSON = JSON.stringify(postData);

	if (actionType === 'downgrade' && !button.attr('data-action-confirmed')) {
		const customData = {
			current_plan_name: body.find('.plan.selected .top_section span').first().text(),
			target_plan_name: $(this).closest('.plan').find('.top_section span').text(),
			show_survey: "",
			message: ""
		};
		$.ajax({
			type: "POST",
			url: '/ajax/advanced_ajax_handler.php?type=check_plan_change_forbidden&_cpt=' + getCookie('_cpt'),
			data: ({postArray: postDataJSON}),
			dataType: "json",
			success: function (data) {
				customData.show_survey = data.success;
				customData.message = data.message;

				openPopup('confirm_downgrade', customData);

				if (data.success) {
					body.on('submit', 'form[name="confirm_downgrade"]', function (event) {
						event.preventDefault();

						// add confirmation tag for a second, re-submit action, then remove confirmation tag
						button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

						closePopup();
					});
				}
			}
		});

		return false;
	}

	button.addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=change_subscription_plan&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				if (data.message.payment_required == 1 && data.message.invoice_id) {

					// upgrade
					goToPage('/checkout/'+data.message.invoice_id, 'checkout', 'checkout', null, data.message.invoice_id, false, null, null);

				} else {

					// downgrade
					button.removeClass('loading');

					var billingPeriodEnd = 'month';

					if (body.find('[name="user[payment_frequency]"]').val() == 'yearly') {
					billingPeriodEnd = 'year';
					}

					generalInfo('show', 'success', 'Your downgrade has been scheduled and will come into effect at the end of this '+ billingPeriodEnd +'.');

				}

				return false;

			}  else {

				button.removeClass('loading');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});



/* AJAX - STRIPE PAYMENTS - PSD2 */
var stripe;
var stripe2;
var elements;
var cardElement;
var cardButton;
var clientSecret;

function initStripe(detail) {

	// init Stripe
	if (detail === 'charge_ex_cc') {
	stripe2 = Stripe(window.stripePublishableKey);
	} else {
	stripe = Stripe(window.stripePublishableKey);
	}

	if (detail === 'elements_enabled') {

		elements = stripe.elements({
		// force english
		locale: 'en',
		});

		cardElement = elements.create('card');
		cardElement.mount('#card-element');
		cardButton = document.getElementById('card-button');
		clientSecret = cardButton.dataset.secret;

	}

}


/* AJAX - STRIPE PAYMENT 2019 - GET PAYMENT INTENT CLIENT SECRET */
function stripeGetSetupIntentSecret() {

	/*if (body.find('[name="stripe_enabled"]').val() !== 'true') {
	return false;
	}*/

	$.ajax({
		url: '/ajax/advanced_ajax_handler.php?type=stripe_create_setupintent',
		dataType: 'json',
		success: function(json) {

			// add client secret to relevant data attr
			body.find('#card-button').attr('data-secret', json.message.client_secret);
			body.find('#card-button').attr('data-setup-intent-id', json.message.id);

			initStripe('elements_enabled');

		}

	});

}


/* AJAX - STRIPE ADD CARD WITHOUT CHARGING */
body.on('click', '.stripe_add_card', function(event) {

	event.preventDefault();

	// if billing address required, validate billing address
	if (body.find('.billing_address').length !== -1) {

		var error = false;
		var errors = 0;

		body.find('[data-required="true"]:visible').each(function() {

			if (!$(this).val()) {
			errors ++;
			$(this).addClass('error');
			} else {
			$(this).removeClass('error');
			}

		});

		if (errors > 0) {
		error = true;
		}

		if (error === true) {
		generalInfo('show', 'error', 'There were errors. Please enter your complete billing details and try again.');
		return false;
		} else {
		generalInfo('hide');
		}

	}

	$(cardButton).addClass('loading');

	  stripe.handleCardSetup(
		clientSecret, cardElement, {}
	  ).then(function(result) {

		if (result.error) {

			$(cardButton).removeClass('loading');

			// report error
			generalInfo('show', 'error', 'Error: '+result.error.message+' (Code: "'+result.error.code+'")');
			//console.log(result.error);

		} else {

			// call to ajax handler to save credit card
			var postData = {
				setup_intent_id: body.find('#card-button').attr('data-setup-intent-id'),
				billing_first_name: body.find('[name="payment_method[add][billing_address][first_name]"]').val(),
				billing_last_name: body.find('[name="payment_method[add][billing_address][last_name]"]').val(),
				billing_address: body.find('[name="payment_method[add][billing_address][address]"]').val(),
				billing_post_code: body.find('[name="payment_method[add][billing_address][post_code]"]').val(),
				billing_state: body.find('[name="payment_method[add][billing_address][state]"]').val(),
				billing_city: body.find('[name="payment_method[add][billing_address][city]"]').val(),
				billing_country_code: body.find('[name="payment_method[add][billing_address][country_code]"]').val(),
			};

			var postDataJSON = JSON.stringify(postData);
			//console.log(postDataJSON);

			$.ajax({
				type: 'POST',
				url: '/ajax/advanced_ajax_handler.php?type=add_stripe_payment_profile',
				dataType: 'json',
				data: ({ postArray: postDataJSON }),
				success: function(json) {

					if (json.success == 1) {

						// reload page if card saved successfully
						generalInfo('show', 'success', 'Your credit card has been added.');
						reloadPage();

						setTimeout( function(){
						closePopup();
						}, 1000);

					} else {

						generalInfo('show', 'error', 'An error occurred. Please try again or contact support.');

						$(cardButton).removeClass('loading');

					}

				}

			});

		}

	  });

});



/* AJAX - STRIPE ACTION ADD CARD WITH CHARGING */
body.on('click', '.stripe_add_and_charge', function(event) {

	event.preventDefault();

	var useCase = $(this).attr('data-use-case') || 'default';

	// if billing address required, validate billing address
	if (body.find('.billing_address').length !== -1) {

		var error = false;
		var errors = 0;

		body.find('[data-required="true"]:visible').each(function() {

			if (!$(this).val()) {
			errors ++;
			$(this).addClass('error');
			} else {
			$(this).removeClass('error');
			}

		});

		if (errors > 0) {
		error = true;
		}

		if (error === true) {
		generalInfo('show', 'error', 'There were errors. Please enter your complete billing details and try again.');
		return false;
		} else {
		generalInfo('hide');
		}

	}

	$(cardButton).addClass('loading');

	stripe.handleCardPayment(
	  clientSecret, cardElement, {
		// not sending any payment_method_data here
		payment_method_data: {}
	  }
	).then(function(result) {

	  if (result.error) {

		  $(cardButton).removeClass('loading');

		  // report error
		  generalInfo('show', 'error', 'Error: '+result.error.message+' (Code: "'+result.error.code+'")');
		  //console.log(result.error);

	  } else {

		  // call to ajax handler to save credit card
		  var postData = {
			  paymentintent_id: body.find('#card-button').attr('data-payment-intent-id'),
			  billing_first_name: body.find('[name="payment_method[add][billing_address][first_name]"]').val(),
			  billing_last_name: body.find('[name="payment_method[add][billing_address][last_name]"]').val(),
			  billing_address: body.find('[name="payment_method[add][billing_address][address]"]').val(),
			  billing_post_code: body.find('[name="payment_method[add][billing_address][post_code]"]').val(),
			  billing_state: body.find('[name="payment_method[add][billing_address][state]"]').val(),
			  billing_city: body.find('[name="payment_method[add][billing_address][city]"]').val(),
			  billing_country_code: body.find('[name="payment_method[add][billing_address][country_code]"]').val(),
		  };

		  var postDataJSON = JSON.stringify(postData);
		  //console.log(postDataJSON);

		  $.ajax({
			  type: 'POST',
			  url: '/ajax/advanced_ajax_handler.php?type=stripe_capture_invoice_payment',
			  dataType: 'json',
			  data: ({ postArray: postDataJSON }),
			  success: function(json) {

				  if (json.success == 1) {

                      gtag('event', 'conversion', {
                          'send_to': 'AW-302531871/EGuACPa1ofgCEJ-KoZAB',
                          'transaction_id': ''
                      });
				  	  if (useCase === 'order_wizard') {
                          // show payment success message
                          generalInfo('show', 'success', 'Payment succeeded. Creating your certificate ...');

                          // submit order wizard
                          submitOrderWizard();
                          return false;
					  }

					  // reload page if payment success
					  reloadPage();

				  } else {

				  	  generalInfo('show', 'error', 'An error occurred. Please try again or contact support.');

					  $(cardButton).removeClass('loading');

				  }

			  }

		  });

	  }

	});

});


/* AJAX - STRIPE ACTION CHARGE EXISTING CARD */
body.on('click', '.charge_existing_cc', function(event) {

	event.preventDefault();

	var useCase = $(this).attr('data-use-case') || 'default';

	var chosenPaymentMethod = body.find('[name="checkout[payment_method][use]"]:checked');
	var paymentMethodID;

	clientSecret = chosenPaymentMethod.attr('data-secret');
	paymentMethodID = chosenPaymentMethod.attr('data-stripe-id');

	initStripe('charge_ex_cc');
	var saveButton = $(this);

	// if billing address required, validate billing address
	if (body.find('.billing_address').length !== -1) {

		var error = false;
		var errors = 0;

		body.find('[data-required="true"]:visible').each(function() {

			if (!$(this).val()) {
			errors ++;
			$(this).addClass('error');
			} else {
			$(this).removeClass('error');
			}

		});

		if (errors > 0) {
		error = true;
		}

		if (error === true) {
		generalInfo('show', 'error', 'There were errors. Please enter your complete billing details and try again.');
		return false;
		} else {
		generalInfo('hide');
		}

	}

	$(this).addClass('loading');

	stripe2.handleCardPayment(
	  clientSecret,
	  { payment_method: paymentMethodID }
	).then(function(result) {

	  if (result.error) {

		  $(saveButton).removeClass('loading');

		  // report error
		  generalInfo('show', 'error', 'Error: '+result.error.message+' (Code: "'+result.error.code+'")');
		  //console.log(result.error);

	  } else {

		  // call to ajax handler to save credit card
		  var postData = {
			  paymentintent_id: body.find('#card-button').attr('data-payment-intent-id'),
			  billing_first_name: body.find('[name="payment_method[add][billing_address][first_name]"]').val(),
			  billing_last_name: body.find('[name="payment_method[add][billing_address][last_name]"]').val(),
			  billing_address: body.find('[name="payment_method[add][billing_address][address]"]').val(),
			  billing_post_code: body.find('[name="payment_method[add][billing_address][post_code]"]').val(),
			  billing_state: body.find('[name="payment_method[add][billing_address][state]"]').val(),
			  billing_city: body.find('[name="payment_method[add][billing_address][city]"]').val(),
			  billing_country_code: body.find('[name="payment_method[add][billing_address][country_code]"]').val(),
		  };

		  var postDataJSON = JSON.stringify(postData);
		  //console.log(postDataJSON);

		  $.ajax({
			  type: 'POST',
			  url: '/ajax/advanced_ajax_handler.php?type=stripe_capture_invoice_payment',
			  dataType: 'json',
			  data: ({ postArray: postDataJSON }),
			  success: function(json) {

				  if (json.success == 1) {

                      gtag('event', 'conversion', {
                          'send_to': 'AW-302531871/EGuACPa1ofgCEJ-KoZAB',
                          'transaction_id': ''
                      });
				  	  if (useCase === 'order_wizard') {
                          // show payment success message
                          generalInfo('show', 'success', 'Payment succeeded. Creating your certificate ...');

                          // submit order wizard
                          submitOrderWizard();
                          return false;
					  }

					  // reload page if payment success
					  reloadPage();

				  } else {

				  	  generalInfo('show', 'error', 'An error occurred. Please try again or contact support.');

					  $(saveButton).removeClass('loading');

				  }

			  }

		  });

	  }

	});

});



/* AJAX - REMOVE PAYMENT METHOD */
body.on('click', '[data-action="account[payment_method][remove]"]', function(event) {

	event.preventDefault();

	var button = $(this);

	var	postData = {
		profile_id: $(this).attr('data-action-id')
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	if (!button.attr('data-action-confirmed')) {

		openPopup('confirm_remove_payment_profile');

		body.on('submit', 'form[name="confirm_remove_payment_profile"]', function(event) {

			event.preventDefault();

			// add confirmation tag for a second, re-submit action, then remove confirmation tag
			button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

		});

		return false;

	}

	body.find('.popup button[type="submit"]').addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=remove_payment_profile&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				// reload page if removed successfully
				generalInfo('show', 'success', 'Payment method removed.');
				reloadPage();

				setTimeout( function(){
				closePopup();
				}, 1000);


			}  else {

				body.find('.popup button[type="submit"]').removeClass('loading');
				generalInfo('show', 'error', translateError(data.message));

			}

			return false;

		}

	});

});



/* AJAX - CHANGE PAYMENT METHOD */
body.on('submit', 'form[name="account[payment_method]"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this).find('button[type="submit"]');

	button.addClass('loading');

	var	postData = {
		profile_id: $(this).find('[name="account[payment_method][switch]"]:checked').val(),
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=switch_payment_profile&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				button.removeClass('loading');

				reloadPage(['show', 'success', 'Payment method switched.']);

			}  else {

				button.removeClass('loading');

				generalInfo('show', 'error', translateError(data.message));

			}

			return false;

		}

	});

});



/* AJAX - CANCEL CHECKOUT */
body.on('click', '[data-action="cancel_checkout"]', function(e) {
	"use strict";
	e.preventDefault();

	var	postData = {
		invoice_id: body.find('[name="checkout[invoice_id]"]').val(),
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	body.addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=cancel_checkout',
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			body.removeClass('loading');

			if (data.success === 1) {

				goToPage('/subscription', 'subscription', 'subscription', null, null, false, null, null);
				return false;

			}  else {

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});


/* AJAX - CANCEL CHECKOUT BY CLOSING CHECKOUT POPUP */
body.on('click', '[data-action="close_popup_cancel_checkout"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this);

	var	postData = {
		invoice_id: body.find('[name="checkout[invoice_id]"]').val(),
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	button.addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=cancel_checkout',
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			closePopup();

			if (data.success === 1) {

				console.log('invoice cancelled by click on [data-action="close_popup_cancel_checkout"]');
				return false;

			}  else {

				console.log('invoice could not be cancelled. error: ' + translateError(data.message));
				return false;

			}

		}

	});

});



/* AJAX - CHANGE PAYMENT FREQUENCY ON CHECKOUT */
body.on('change', '[name="checkout[payment_frequency]"]', function(e) {
	"use strict";
	e.preventDefault();

	var selectedFrequency = body.find('[name="checkout[payment_frequency]"]:checked').val();
	var planID = body.find('[name="checkout[plan_id]"]').val();

	var button = $(this);

	var	postData = {
		plan_id: planID,
		payment_frequency: selectedFrequency,
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	body.find('.form_row.radio.payment_frequency').addClass('disabled');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=change_subscription_plan&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1 && data.message.payment_required == 1 && data.message.invoice_id) {

				// go to new invoice
				goToPage('/checkout/'+data.message.invoice_id, 'checkout', 'checkout', null, data.message.invoice_id, false, null, null);

			}  else {

				body.find('.form_row.radio.payment_frequency').removeClass('disabled');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});



/* CHECKOUT - SWITCH BETWEEN EXISTING & ADD NEW PAYMENT METHOD */
body.on('click', '[data-action="checkout_switch_new_existing_payment_method"]', function() {

	var actionType = $(this).attr('data-action-type');

	var addNewContainer = body.find('.checkout_add_new_pm');
	var useExistingContainer = body.find('.checkout_existing_pm');

	generalInfo('hide');

	if (actionType === 'add_new') {
	useExistingContainer.hide();
	addNewContainer.fadeIn(150);
	} else {
	addNewContainer.hide();
	useExistingContainer.fadeIn(150);
	}

});



/* AJAX - RESET ACCESS KEY */
body.on('click', '[data-action="reset_access_key"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this);

	if (!button.attr('data-action-confirmed')) {

		openPopup('confirm_reset_access_key');

		body.on('submit', 'form[name="confirm_reset_access_key"]', function(event) {

			event.preventDefault();

			// add confirmation tag for a second, re-submit action, then remove confirmation tag
			button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

			closePopup();

		});

		return false;

	}

	button.html('Wait ...');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=reset_access_key&_cpt=' + getCookie('_cpt'),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			body.removeClass('loading');

			if (data.success === 1) {

				reloadPage(['show', 'success', 'Your API key has been reset.']);
				return false;

			}  else {

				button.html('RESET KEY');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});


/* HELPER FUNCTION TO CLEAN GET VARIABLES IN LOAD TABLE FUNCTION */
function cleanTableGetVariable(variable) {

	if (typeof variable === 'undefined') {
	return false;
	}

	if (variable) {

		// convert to string
		variable = variable + '';

		return variable.replace('search:', '').replace('page:', '');

	}

}


// HELPER FUNCTION TO NORMALIZE DATE (FOR BROWSERS LIKE SAFARI)
function normalizeDate(input, format) {
  format = format || 'yyyy-mm-dd'; // default format
  var parts = input.match(/(\d+)/g),
      i = 0, fmt = {};
  // extract date-part indexes from the format
  format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; });

  return new Date(parts[fmt['yyyy']], parts[fmt['mm']]-1, parts[fmt['dd']]);
}

var entityMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '/': '&#x2F;',
    '`': '&#x60;',
    '=': '&#x3D;'
};

function escapeHtml (string) {
    return String(string).replace(/[&<>"'`=\/]/g, function (s) {
        return entityMap[s];
    });
}

/* AJAX - LOAD/UPDATE CERTIFICATES TABLE */
function loadTable() {

	parameterStatus = body.find('[name="additional_parameter[status]"]').val() || 'issued';
	parameterSearch = cleanTableGetVariable(body.find('[name="additional_parameter[search]"]').val()) || '';
	parameterLimit = 10;
	parameterPage = cleanTableGetVariable(body.find('[name="additional_parameter[pageno]"]').val() ? body.find('[name="additional_parameter[pageno]"]').val() : 1) || 1;

	const protectionEnabled = $("section.list").attr('data-protection-enabled') === "true";
	const showProtectionColumn = (parameterStatus === "issued" || parameterStatus === "expiring_soon");
	var	postData = {
		certificate_status: parameterStatus,
		search: parameterSearch,
		limit: parameterLimit,
		page: parameterPage,
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	var table = body.find('section.list');

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_list_certificates&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: 'json',
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(response){

            // ACME certificates display information
            if(response.message.acmeLocked === true) {
                // display message
                let alertsContainer = body.find('.content aside.alerts');
                let message = "";
                if(response.message.acmeUsageLevel === "MEDIUM") {
                    message = "Note: Your account is holding more than 100 ACME certificates. For using the Dashboard or API with this amount of ACME certificates you have to upgrade at least to the ZeroSSL basic plan."
                } else if(response.message.acmeUsageLevel === "HIGH") {
                    message = "Note: Your account is holding more than 100.000 ACME certificates. For using the Dashboard or API with this amount of ACME certificates you have to upgrade at least to the ZeroSSL premium plan."
                }
                alertsContainer.html('<p class="alert info">'+message+'</p>');
            }

			// table metadata
			var metaContent;
			var metaNumberPages = Math.ceil(response.message.total_count / response.message.limit);

			var pagesPlural = metaNumberPages > 1 ? 'pages' : 'page';
			var resultsPlural = response.message.total_count > 1 ? 'results' : 'result';

			metaContent = 'Showing <strong>'+response.message.total_count+' '+resultsPlural+' </strong> on '+metaNumberPages+' '+pagesPlural;

			// generate pagination section
			generatePaginationSection(response.message.total_count);

			if (response.message.total_count > 0) {
				let rowClass = "";
				if (showProtectionColumn) {
					rowClass = "has-protection-column";
				}

				// table headings are static
				var tableContent = '<li class="headings ' + rowClass + '"> <div class="title"> <span>Type</span> </div><div class="domains"> <span>Domains</span> </div><div class="status"> <span>Status</span> </div>';
				if (showProtectionColumn) {
					tableContent += '<div class="protection"><span>Protect</span></div>';
				}
				tableContent += '<div class="expiration"> <span>Expires</span> </div><div class="actions"> <span></span> </div> </li>';

				// table content rows are dynamic
				$.each(response.message.results, function(i) {

					var certHash = response.message.results[i].id;
					var certCommonName = response.message.results[i].common_name;
					var certStatus = response.message.results[i].status;
					var certIsMultiDomain = false;
                    var certDomainProtection = response.message.results[i].protection ?? "none";

					var certExpirationDate = new Date(normalizeDate(response.message.results[i].expires));

					// calculate days to expiration, this is used further
					// below to identify which certs are "expiring soon"
					var currentDate = new Date();
					var diffTime = Math.abs(currentDate - certExpirationDate);
					var diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

					var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
					var d = certExpirationDate.getDate();
					var m =  months[certExpirationDate.getMonth()];
					var y = certExpirationDate.getFullYear();

					certExpirationDate = m + ' ' + d + ', ' + y;

					var certType;

					switch (parseInt(response.message.results[i].type)) {

						case 1:
						certType = '90-Day SSL';
						break;

						case 2:
						certType = '90-Day Wildcard';
						break;

						case 3:
						certType = '90-Day SSL';
						certIsMultiDomain = true;
						break;

						case 4:
						certType = '1-Year SSL';
						break;

						case 5:
						certType = '1-Year Wildcard';
						break;

						case 6:
						certType = '1-Year SSL';
						certIsMultiDomain = true;
						break;

						default:
						certType = 'Certificate';
						break;

					}

					var certStatus;
					var certStatusClass;

					var primaryAction;
					var dropdownActions = [];

                    let brandValidation = false;

					switch (response.message.results[i].status) {

						case 'draft':
						certStatus = 'Draft';
						certStatusClass = 'draft';
						primaryAction = 'continue_certificate';
						dropdownActions.push('copy_hash', 'cancel_certificate');
						break;

						case 'issued':

							// expiring_soon is not a real API status, which is
							// why we need to check if expiry date below 30 days
							if (diffDays <= 30) {
							certStatus = 'Expiring Soon';
							certStatusClass = 'expiring';
							primaryAction = 'renew_certificate';
							dropdownActions.push('copy_hash', 'download_certificate', 'revoke_certificate');
							} else {
							certStatus = 'Issued';
							certStatusClass = 'issued';
							primaryAction = 'install_certificate';
							dropdownActions.push('copy_hash', 'download_certificate', 'revoke_certificate');
							}
						break;

						case 'pending_validation':
						certStatus = 'Pending Validation';
						certStatusClass = 'pending_validation';
						primaryAction = 'validation_status';
						dropdownActions.push('copy_hash', 'cancel_certificate');
                        brandValidation = (response.message.results[i].brand_validation === "false") ? false : !!response.message.results[i].brand_validation
						break;

						case 'expired':
						certStatus = 'Expired';
						certStatusClass = 'expired';
						primaryAction = 'renew_certificate';
						dropdownActions.push('copy_hash');
						break;

						case 'cancelled':
						certStatus = 'Cancelled';
						certStatusClass = 'cancelled';
						primaryAction = 'copy_hash';
						//dropdownActions.push('copy_hash');
						break;

                        case 'revoked':
                        certStatus = 'Revoked';
                        certStatusClass = 'revoked';
                        primaryAction = 'copy_hash';
                        break;

                        default:
						certStatus = 'Unknown';
						certStatusClass = 'draft';
						primaryAction = 'copy_hash';
						//dropdownActions.push('copy_hash');
						break;

					}

					// actions
					var certActions = '';
					var additionalPrimaryButtonClass = '';

					if (dropdownActions.length < 1) {
					additionalPrimaryButtonClass = 'alone';
					}

					switch (primaryAction) {

						case 'copy_hash':
						certActions += '<a class="button primary '+additionalPrimaryButtonClass+'" title="Copy Certificate Hash" data-action="copy_to_clipboard" data-action-id="'+certHash+'" href="javascript:void(0)">Copy Hash</a>';
						break;

						case 'install_certificate':
						certActions += '<a class="button primary '+additionalPrimaryButtonClass+'" title="Install Certificate" href="/certificate/install/'+certHash+'" data-ajax="true" data-ajax-get-file="install" data-ajax-get-page="install" data-ajax-get-id="'+certHash+'" href="javascript:void(0)">Install</a>';
						break;

						case 'validation_status':
						certActions += '<a class="button primary '+additionalPrimaryButtonClass+'" title="Validation Status" href="/certificate/verify/'+certHash+'/status" data-ajax="true" data-ajax-get-file="verify" data-ajax-get-page="verify" data-ajax-get-type="status" data-ajax-get-id="'+certHash+'" href="javascript:void(0)">Status</a>';
						break;

						case 'continue_certificate':
						certActions += '<a class="button primary '+additionalPrimaryButtonClass+'" title="Validate Certificate" href="/certificate/verify/'+certHash+'" data-ajax="true" data-ajax-get-file="verify" data-ajax-get-page="verify" data-ajax-get-id="'+certHash+'" href="javascript:void(0)">Verify</a>';
						break;

						case 'renew_certificate':
						certActions += '<a class="button primary '+additionalPrimaryButtonClass+'" title="Renew Certificate" href="/certificate/renew/'+certHash+'" data-ajax="true" data-ajax-get-file="order" data-ajax-get-page="order" data-ajax-get-id="'+certHash+'">Renew</a>';
						break;

					}

					// show dropdown actions if available
					if (dropdownActions.length > 0) {

						certActions += '<a data-dropdown="toggle" href="javascript:void(0)"></a>';
						certActions += '<ul data-dropdown="menu" class="dropdown_menu">';

						if ($.inArray('copy_hash', dropdownActions) != -1) {
						certActions += '<li><a title="Copy Certificate Hash" data-action="copy_to_clipboard" data-action-id="'+certHash+'" href="javascript:void(0)">Copy Hash</a></li>';
						}

						if ($.inArray('cancel_certificate', dropdownActions) != -1) {
							let totalDomains = 1; // Default to 1

							// Only count additional domains for multi-domain certificates
							if (certIsMultiDomain === true && response.message.results[i].additional_domains) {
								let additionalDomainsArray = response.message.results[i].additional_domains.split(',');

								// Separate valid domains and IPs
								let validDomains = additionalDomainsArray.filter(domain => !isIPAddress(domain));
								let ipAddresses = additionalDomainsArray.filter(domain => isIPAddress(domain));

								totalDomains = validDomains.length + ipAddresses.length + 1;
							}

							certActions += '<li><a title="Cancel Certificate" data-action="cancel_certificate" data-action-id="' + certHash + '" data-total-domains="' + totalDomains + '" href="javascript:void(0)">Cancel Certificate</a></li>';
						}


						if ($.inArray('download_certificate', dropdownActions) != -1) {
						certActions += '<li><a href="javascript:void(0)" title="Download Certificate" data-action="wizard[install][download_certificate]" data-action-id="'+certHash+'" data-action-filename="'+certCommonName+'">Download Certificate</a></li>';
						}

						if ($.inArray('renew_certificate', dropdownActions) != -1) {
						certActions += '<li><a title="Renew Certificate" href="/certificate/renew/'+certHash+'" data-ajax="true" data-ajax-get-file="order" data-ajax-get-page="order" data-ajax-get-id="'+certHash+'">Renew Certificate</a></li>';
						}

                        if ($.inArray('revoke_certificate', dropdownActions) != -1) {
                            certActions += '<li><a title="Revoke Certificate" data-action="revoke_certificate" data-action-id="'+certHash+'" href="javascript:void(0)">Revoke Certificate</a></li>';
                        }

						certActions += '</ul>';

					}
					// adding function to check if domain is IP
					function isIPAddress(domain) {
						return /^(?:\d{1,3}\.){3}\d{1,3}$/.test(domain) ||
							/^(?:[a-fA-F0-9:]+:+)+[a-fA-F0-9]+$/.test(domain);
					}

					var certMultiDomainViewer = '';


					// if more than one domain in cert and type is 3 (90-day multi-domain) or 6 (1-year multi-domain)
					// Check if the certificate has additional domains

					if (response.message.results[i].additional_domains && response.message.results[i].additional_domains.split(',').length > 0) {
						// More than one domain and cert is multi-domain type
						if (certIsMultiDomain === true) {
							let additionalDomainsArray = response.message.results[i].additional_domains.split(',');

							// Separate valid domains and IPs
							let validDomains = additionalDomainsArray.filter(domain => !isIPAddress(domain));
							let ipAddresses = additionalDomainsArray.filter(domain => isIPAddress(domain));

							let totalDomains = validDomains.length + ipAddresses.length;

							if (totalDomains > 0) {
								// Show full count including IPs and allow user to copy them
								let tooltipText = 'Multi-Domain Certificate (' + certType + ') with ' + (totalDomains + 1) + ' entries. Click to see all protected domains.';
								let actionId = certCommonName + ',' + additionalDomainsArray.join(',');

								certMultiDomainViewer = `<small class="custom" data-tooltip="${tooltipText}" data-action="view_cert_domains" data-action-id="${actionId}">${totalDomains + 1}</small>`;
							} else {
								// If all entries are IPs, still show count
								certMultiDomainViewer = `<small class="custom" data-tooltip="Multi-Domain Certificate includes only IP addresses, which are not fully supported. Click to see details." data-action="view_cert_domains" data-action-id="${certCommonName},${ipAddresses.join(',')}">${ipAddresses.length + 1}</small>`;
							}
						}
					}



					let brandValidationHtml = '';

					if (brandValidation) {
						brandValidationHtml = '<i class="brand_validation" data-tooltip="Brand validation: Verification has passed, but our team has to check manually if we are allowed to issue a certificate for that domain. This may take a certain amount of time."></i>';
					}

					let protectCta = "";
					let protectionStatus = certDomainProtection;  // This is where we determine the protection status (monitor, premium, none)

					// Check if it's an IP address
					if (isIPAddress(certCommonName)) {
						// IP addresses cannot be protected
						protectCta = '<a class="protect-domain-certlist protection-' + certDomainProtection + '" href="#" title="Protection for IP addresses is not available"><span class="protection custom ' + certDomainProtection + '" data-ptooltip="Protect for IP addresses is not available">n/a</span></a>';
					} else if (certStatusClass === 'issued' || certStatusClass === 'expiring') {
						// Handle the protection for valid domains (not IPs)
						let cptooltip = 'Protect and monitor this domain using ZeroSSL Protect.';
						let cpText = '';

						// Determine the protection level
						if (protectionStatus === "monitor") {
							cptooltip = 'Protected by ZeroSSL surface protect.';
							cpText = 'Surface';
						} else if (protectionStatus === "premium") {
							cptooltip = 'Protected by ZeroSSL core protect.';
							cpText = 'Core';
						} else {
							cptooltip = 'Domain is not protected';
							cpText = 'None';
						}

						// Generate protection button for domains
						protectCta = '<a class="protect-domain-certlist protection-' + certDomainProtection + '" href="/protection?protect_domain='+certCommonName+'"><span class="protection custom ' + certDomainProtection + '" data-ptooltip="' + cptooltip + '">' + cpText + '</span></a>';

						if (!protectionEnabled) {
							protectCta = '<a href="/protection"><span class="protection none"> Try Feature</a>';
						}
					}
					// Build the row for the certificate
					var thisRow = '<li class="' + rowClass + '"> <div class="title"> <span>' + certType + '</span> </div><div class="domains custom fulldomain" data-tooltip="' + certCommonName + '"> <span class="custom" style="cursor:pointer;" data-action="view_cert_domains" data-action-id="' + certCommonName + ',' + response.message.results[i].additional_domains + '">' + certCommonName + '</span>' + certMultiDomainViewer + ' </div><div class="status ' + certStatusClass + '"> <span>' + certStatus + '</span> ' + brandValidationHtml + ' </div>';

					if (showProtectionColumn) {
						thisRow += '<div class="protection">' + protectCta + '</div>';
					}

					thisRow += '<div class="expiration"> <span>' + certExpirationDate + '</span> </div><div class="actions dropdown"> ' + certActions + ' </div></li>';

					tableContent += thisRow;


				});

				table.find('ul').html(tableContent);

			} else {

				metaContent = '';

				// no results
				table.find('ul').html('<li class="no_results">No Results <a href="/certificate/new" data-ajax="true" data-ajax-get-file="order" data-ajax-get-page="order">Create Certificate</a></li>');

			}

			// show table metadata
			body.find('span.pagination_meta').html(metaContent);

		}

	});

}


/* COPY TO CLIPBOARD */
body.on('click', '[data-action="copy_to_clipboard"]', function() {
	"use strict";

	var container = $(this);
	var valueToCopy = container.attr('data-action-id');

    var $temp = $("<input>");
    $("body").append($temp);
    $temp.val(valueToCopy).select();

    document.execCommand("copy");

    $temp.remove();

	generalInfo('show', 'success', 'Certificate hash copied to clipboard.');

});


/* CERTIFICATE LIST - GENERATE PAGINATION SECTION */
function generatePaginationSection(totalCount) {

	var additionalStatusFilter = ['/'+escapeHtml(parameterStatus), '&status='+escapeHtml(parameterStatus)];

	var paginationContent = '';

	// calculate number of pages and generate buttons
	var numberOfPages = Math.ceil(totalCount / parameterLimit);

	var previousDisabled = parameterPage < 2 ? 'disabled' : '';
	var nextDisabled = parameterPage >= numberOfPages ? 'disabled' : '';

	if (!totalCount) {
	previousDisabled = 'disabled';
	nextDisabled = 'disabled';
	}

	var previousPage = parameterPage - 1;
	var nextPage = parseInt(parameterPage) + 1;

	// back to start button
	paginationContent += '<a href="/certificates'+additionalStatusFilter[0]+'/search:'+escapeHtml(parameterSearch) +'/page:1" data-ajax="true" data-ajax-get-file="certificates" data-ajax-get-page="certificates" data-ajax-get-type="" data-ajax-get-parameters="'+additionalStatusFilter[1]+'&search=search:'+escapeHtml(parameterSearch)+'&pageno=page:1" class="paginate_button start '+previousDisabled+'" tabindex="0"></a>';

	// previous button
	paginationContent += '<a href="/certificates'+additionalStatusFilter[0]+'/search:'+escapeHtml(parameterSearch)+'/page:'+previousPage+'" data-ajax="true" data-ajax-get-file="certificates" data-ajax-get-page="certificates" data-ajax-get-type="" data-ajax-get-parameters="'+additionalStatusFilter[1]+'&search=search:'+escapeHtml(parameterSearch)+'&pageno=page:'+previousPage+'" class="paginate_button previous '+previousDisabled+'" tabindex="0"></a>';

	for (index = 1; index <= numberOfPages; index++) {

		var currentClass = index == parameterPage ? 'current' : '';

		// calculate difference between loop index and current page	number
		var differenceToIndex = parameterPage - index;
		differenceToIndex = (differenceToIndex < 1) ? (differenceToIndex * -1) : differenceToIndex;

		var paginationReach = 2;
		var maxPagesShowing = 1 + (2 * paginationReach);

		if (parameterPage == 1 || parameterPage == numberOfPages) {
		paginationReach = 4;
		} else if (parameterPage == 2 || parameterPage == (numberOfPages - 1)) {
		paginationReach = 3;
		}

		// show only pages that are X larger or X smaller than the current page number
		if (differenceToIndex <= paginationReach) {
		paginationContent += '<a href="/certificates'+additionalStatusFilter[0]+'/search:'+escapeHtml(parameterSearch)+'/page:'+index+'" data-ajax="true" data-ajax-get-file="certificates" data-ajax-get-page="certificates" data-ajax-get-type="" data-ajax-get-parameters="'+additionalStatusFilter[1]+'&search=search:'+escapeHtml(parameterSearch)+'&pageno=page:'+index+'" class="paginate_button '+currentClass+'" data-table-page="'+index+'" tabindex="0">'+index+'</a>';
		}

	}

	// next button
	paginationContent += '<a href="/certificates'+additionalStatusFilter[0]+'/search:'+escapeHtml(parameterSearch)+'/page:'+nextPage+'" data-ajax="true" data-ajax-get-file="certificates" data-ajax-get-page="certificates" data-ajax-get-type="" data-ajax-get-parameters="'+additionalStatusFilter[1]+'&search=search:'+escapeHtml(parameterSearch)+'&pageno=page:'+nextPage+'" class="paginate_button next '+nextDisabled+'" tabindex="0"></a>';

	// go to last page button
	paginationContent += '<a href="/certificates'+additionalStatusFilter[0]+'/search:'+escapeHtml(parameterSearch)+'/page:'+numberOfPages+'" data-ajax="true" data-ajax-get-file="certificates" data-ajax-get-page="certificates" data-ajax-get-type="" data-ajax-get-parameters="'+additionalStatusFilter[1]+'&search=search:'+escapeHtml(parameterSearch)+'&pageno=page:'+numberOfPages+'" class="paginate_button end '+nextDisabled+'" tabindex="0"></a>';

	body.find('[data-table="pagination"]').html(paginationContent);

}


/* CERTIFICATE LIST - SEARCH */
body.on('submit', '[name="table_search"]', function(event) {

	event.preventDefault();

	var additionalStatusFilter = ['/'+escapeHtml(parameterStatus), '&status='+escapeHtml(parameterStatus)];

	var searchTerm = $(this).find('[data-table="search"]').val();

	goToPage('/certificates'+additionalStatusFilter[0]+'/search:'+searchTerm+'/page:1', currentFile, currentPage, currentType, currentID, false, null, additionalStatusFilter[1]+'&search=search:'+searchTerm+'&pageno=page:1', false);

});


/* CERTIFICATE LIST - VIEW CERT DOMAINS */
body.on('click', '[data-action="view_cert_domains"]', function() {

	var domainArray = $(this).attr('data-action-id');

	openPopup('view_cert_domains', domainArray);

});



/* AJAX - CANCEL CERTIFICATE */

function updateCancelPopup(certCount, totalDomains) {
	let warningMessage = document.querySelector("#confirm_cancel_certificate .cancelWarningMessage");
	if (!warningMessage) {
		return {
			success: false,
			error: 'Warning message element not found',
			details: {
				selector: "#confirm_cancel_certificate .cancelWarningMessage",
				containerExists: !!document.querySelector("#confirm_cancel_certificate"),
				totalDomains: totalDomains
			}
		};
	}

	totalDomains = parseInt(totalDomains, 10) || 1;

	try {
		if (totalDomains > 1) {
			warningMessage.innerHTML = `Cancelling this multi-domain certificate will free up <strong>${totalDomains}</strong> credits on your account.`;
		} else {
			warningMessage.innerHTML = `Cancelling this certificate will free up <strong>1</strong> credit on your account.`;
		}

		// Return success object
		return {
			success: true,
			message: 'Warning message updated successfully'
		};
	} catch (error) {
		// Catch any unexpected errors during innerHTML setting
		return {
			success: false,
			error: 'Failed to update warning message',
			details: error.message
		};
	}
}

body.on('click', '[data-action="cancel_certificate"]', function(event) {

	event.preventDefault();

	let button = $(this);

	const certId = button.attr('data-action-id');
	const certList = $('[data-action="cancel_certificate"][data-selected="true"]');
	const certCount = certList.length || 1;

	const totalDomains = parseInt(button.attr('data-total-domains'), 10) || 1;


	const postData = {
		id: certId,
		count: certCount,
		total_domains: totalDomains
	};

	updateCancelPopup(certCount, totalDomains);

	const postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	if (!button.attr('data-action-confirmed')) {

		openPopup('confirm_cancel_certificate', postData, function () {
			setTimeout(() => {
				updateCancelPopup(certCount, totalDomains);
			}, 100); // Ensure the pop-up is loaded
		});
		body.on('submit', 'form[name="confirm_cancel_certificate"]', function(event) {

			event.preventDefault();

			// add confirmation tag for a second, re-submit action, then remove confirmation tag
			button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

		});

		return false;

	}

	body.find('.popup button[type="submit"]').addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_cancel_certificate&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			if (data.success === 1) {

				// reload page if removed successfully
				generalInfo('show', 'success', 'Certificate cancelled.');
				reloadPage();

				setTimeout( function(){
				closePopup();
				}, 1000);


			}  else {

				body.find('.popup button[type="submit"]').removeClass('loading');
				generalInfo('show', 'error', translateError(data.message));

			}

			return false;

		}

	});

    $.ajax({
        type: "POST",
        url: '/ajax/advanced_ajax_handler.php?type=zerossl_cancel_certificate&_cpt=' + getCookie('_cpt'),
        data: ({ postArray: postDataJSON }),
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            //alert(textStatus + ', ' + errorThrown);
        },
        success: function(data){

            if (data.success === 1) {

                // reload page if removed successfully
                generalInfo('show', 'success', 'Certificate cancelled.');
                reloadPage();

                setTimeout( function(){
                    closePopup();
                }, 1000);


            }  else {

                body.find('.popup button[type="submit"]').removeClass('loading');
                generalInfo('show', 'error', translateError(data.message));

            }

            return false;

        }

    });

});

/* AJAX - REVOKE CERTIFICATE */
body.on('click', '[data-action="revoke_certificate"]', function(event) {

    event.preventDefault();

    let button = $(this);

    const	postData = {
        id: $(this).attr('data-action-id'),
        reason: $("#revocation_reason").val()
    };

    const postDataJSON = JSON.stringify(postData);

    if (!button.attr('data-action-confirmed')) {

        openPopup('confirm_revoke_certificate');

        body.on('submit', 'form[name="confirm_revoke_certificate"]', function(event) {

            event.preventDefault();

            // add confirmation tag for a second, re-submit action, then remove confirmation tag
            button.attr('data-action-confirmed', 'true').click().removeAttr('data-action-confirmed');

        });

        return false;

    }

    body.find('.popup button[type="submit"]').addClass('loading');

    $.ajax({
        type: "POST",
        url: '/ajax/advanced_ajax_handler.php?type=zerossl_revoke_certificate&_cpt=' + getCookie('_cpt'),
        data: ({ postArray: postDataJSON }),
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            //alert(textStatus + ', ' + errorThrown);
        },
        success: function(data){

            if (data.success === 1) {

                // reload page if removed successfully
                generalInfo('show', 'success', 'Certificate revoked.');
                reloadPage();

                setTimeout( function(){
                    closePopup();
                }, 1000);


            }  else {

                body.find('.popup button[type="submit"]').removeClass('loading');
                generalInfo('show', 'error', translateError(data.message));

            }

            return false;

        }

    });

});


/* ORDER - DOMAINS PREVIEW */
function processDomainsToProtect(that, trigger) {

	that.val(that.val().replace(/['"]/gi, ''));

    let thisValue = that.val();

    let isSubdomain = false;
    let isWildcard = false;
    let isMultiDomain = false;
    let isIpAddress = false;

    // trim leading and trailing white-spaces
	thisValue = $.trim(thisValue);

	// check for /paths
	if (thisValue.indexOf('/') >= 0) {
	    thisValue = thisValue.substring(0, thisValue.indexOf('/'));
	}

	// check if multiple domains
	if (body.find('.domain_collection .domain').length > 1) {
	    isMultiDomain = true;
	}

	// remove "www." from domain, but only if not multi-domain
    let wwwSubdomainWasRemoved = false;
	const alreadyContainsWWW = thisValue.indexOf('www.') >= 0;
	let originalValue = thisValue; // Before it possibly gets www stripped

	// do strip www from input, when input already contains www, in order to prevent www.www situations
	// and if it is not a multidomain
	// and if input is not a subdomain (ZERO-224)
	if (alreadyContainsWWW >= 0 && isMultiDomain !== true && subDomain(thisValue) === false) {
	    thisValue = thisValue.replace(/www./, '');
        wwwSubdomainWasRemoved = true;
	}

    that.closest('.domain').find('.preview span').show();
    that.closest('.domain').find('.remove_domain').remove(); // always remove the removal buttons first

	// check for existing submit values that have the same content ("not" the current submit value)
	if (thisValue && body.find('[name="wizard[order][domains][domain][submit_value]"][value="'+thisValue+'"]').not($(that).closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]')).length > 0) {
		that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val('');

		that.closest('.domain').find('.preview').show();
		that.closest('.domain').find('.preview').addClass('error');
		that.closest('.domain').find('.preview span:nth-child(1)').html('Duplicate');
		that.closest('.domain').find('.preview span:nth-child(2)').html('');
		return false;

	}

	if (ipAddress(thisValue)) {
	    isIpAddress = true;
    } else if (subDomain(thisValue)) {
	    isSubdomain = true;
	}

	// check for *. wildcard indicator or checked wildcard checkbox
	if (thisValue.indexOf('*.') >= 0 || body.find('[name="wizard[order][domains][wildcard]"]').is(':checked')) {
        thisValue = thisValue.replace('*.', '');
		isWildcard = true;
		wildcardMode('on');
		// if multiple domains entered, move the wildcard domain to the top of domains
		if (body.find('.domain_collection .domain').length > 1) {
		$(that).closest('.domain').detach().insertBefore('.domain_collection .domain:first');
		}

	}

	// now validate domain
	if (isValidDomain(thisValue) && !isBlockedDomain(thisValue)) {

        that.closest('.domain').find('.preview').removeClass('error');

        // add submit value
        that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val(thisValue);

        // add non-www preview value
        that.closest('.domain').find('.preview span:nth-child(1)').html(thisValue);

        if (isSubdomain === true && isWildcard !== true) {

            that.closest('.domain').find('.preview span:nth-child(2)').hide();

        } else if (isWildcard === true && isSubdomain === true) {

            const domainParts = thisValue.split('.');
			domainParts.unshift("*");
			const wildCardSubDomainValue = domainParts.join(".");

            that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val(wildCardSubDomainValue);
            that.closest('.domain').find('[name="wizard[order][domains][domain]"]').val(wildCardSubDomainValue);

            that.closest('.domain').find('.preview span:nth-child(1)').html(wildCardSubDomainValue);
            that.closest('.domain').find('.preview span:nth-child(2)').hide();

        } else if (isWildcard === true) {

            that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val('*.' + thisValue);
            that.closest('.domain').find('[name="wizard[order][domains][domain]"]').val('*.' + thisValue);

            that.closest('.domain').find('.preview span:nth-child(1)').html('*.' + thisValue);
            that.closest('.domain').find('.preview span:nth-child(2)').hide();

        } else if (isMultiDomain === true) {

            // empty & hide all (not only this) auto-included www-versions
            body.find('.preview span:nth-child(2)').html('').hide();
        } else if (isIpAddress) {
            that.closest('.domain').find('.preview span:nth-child(2)').hide();

        } else {
			const domainEl = that.closest('.domain');
			const firstChildSpan = domainEl.find('.preview span:nth-child(1)');
			const secondChildSpan = domainEl.find('.preview span:nth-child(2)');
			firstChildSpan.removeClass('preview-with-www');

			// Correct the layout if there are two options shown. The first should be the original value the user typed
			if (originalValue.indexOf("www.") >= 0) {
				firstChildSpan.html(originalValue);
				firstChildSpan.addClass("preview-with-www");
				secondChildSpan.html(thisValue); // Non-www version
				secondChildSpan.after('<i class="custom remove_domain" data-removeDomain="root" data-tooltip="Remove root domain"></i>');
			} else {
				secondChildSpan.html('www.' + thisValue); // www version
				secondChildSpan.addClass("preview-with-www");
				secondChildSpan.after('<i class="custom remove_domain" data-removeDomain="www" data-tooltip="Remove www subdomain"></i>');
			}
			secondChildSpan.show();
        }
    } else if (isBlockedDomain(thisValue)) {
        // empty submit value
        that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val('');

        that.closest('.domain').find('.preview').addClass('error');
        that.closest('.domain').find('.preview span:nth-child(1)').html('Currently, we are not able to issue certificates for this domain (<a target="_blank" style="pointer-events: auto;" href="https://help.zerossl.com/hc/en-us/articles/360060119833-Restricted-Countries">learn more</a>).');
        that.closest('.domain').find('.preview span:nth-child(2)').html('');
	} else {
		// empty submit value
		that.closest('.domain').find('[name="wizard[order][domains][domain][submit_value]"]').val('');

		// empty values do not cause error
		if (!thisValue) {
			return;
		}

		that.closest('.domain').find('.preview').addClass('error');
		that.closest('.domain').find('.preview span:nth-child(1)').html('Please enter a valid domain');
		that.closest('.domain').find('.preview span:nth-child(2)').html('');
	}

	that.closest('.domain').find('.preview').show();

}


var _changeInterval = null;

body.on('keyup', '[name="wizard[order][domains][domain]"]', function() {

	// always mark domains-step uncompleted when changes happen
	body.find('[data-step-id="wizard[order][domains]"]').removeClass('complete');

	var that = $(this);

	// if no value (deleted all), simply process right away
	if (!($.trim(that.val()))) {
	processDomainsToProtect(that, 'keyup');
	return false;
	}

	// if value provided, resume function
	$(that).closest('.domain').addClass('loading');

	clearInterval(_changeInterval);

	// 500ms delay to make sure user has stopped typing
    _changeInterval = setInterval(function() {

        clearInterval(_changeInterval);
		processDomainsToProtect(that, 'keyup');

		body.find('.domain').removeClass('loading');

    }, 500);

});


/* ORDER - WILDCARD SWITCH */
body.on('change', '[name="wizard[order][domains][wildcard]"]', function() {

	if ($(this).is(':checked')) {

		wildcardMode('on');

	} else {

		wildcardMode('off');

	}

	processDomainsToProtect(body.find('.domain_collection .domain:first-of-type input'), 'wildcardSwitch');

});

function wildcardMode(action, type) {
	if (action === 'off') {

		if (body.find('form[name="wizard[order][domains]"]').hasClass('is_wildcard')) {

			// strip away *. characters from all places (preview, submit-value and entered-value)
            var valueWithoutWildCard = body.find('.domain_collection .domain:first-of-type .preview:not(.error) span:first-of-type').text().replace('*.', '');
            if (valueWithoutWildCard === "") {
                valueWithoutWildCard = body.find('.domain_collection .domain:first-of-type [name="wizard[order][domains][domain]"]').val().replace('*.', '');
            }

            body.find('.domain_collection .domain:first-of-type .preview span:first-of-type').text(valueWithoutWildCard);
			body.find('.domain_collection .domain:first-of-type [name="wizard[order][domains][domain][submit_value]"]').val(valueWithoutWildCard);
			body.find('.domain_collection .domain:first-of-type [name="wizard[order][domains][domain]"]').val(valueWithoutWildCard);
		}

		body.find('form[name="wizard[order][domains]"]').removeClass('is_wildcard');
		body.find('.enter_domain_heading').text('Enter Domains');
		body.find('[name="wizard[order][domains][wildcard]"]').attr("checked", false);
	} else {

		body.find('form[name="wizard[order][domains]"]').addClass('is_wildcard');
		body.find('.enter_domain_heading').text('Enter Domain');
		body.find('[name="wizard[order][domains][wildcard]"]').attr("checked", true);

	}
}


/* ORDER - ADD & REMOVE DOMAIN */
body.on('click', '[data-action="wizard[order][domains][add_domain]"]', function() {

	// max number of alled domains
	var maxAllowedDomains = 100;

	if (body.find('.domain_collection .domain').length >= maxAllowedDomains) {

		generalInfo('show', 'info', 'Your plan allows for no more than 100 domains per certificate. For questions, please <a target="_blank" href="https://zerossl.com/contact">contact support</a>.');
		return false;

	} else {

		generalInfo('hide');

	}

	var newDomainRow = '<div class="domain"> <input type="hidden" name="wizard[order][domains][domain][submit_value]"> <input type="text" name="wizard[order][domains][domain]"  maxlength="64" placeholder="Enter Domain" value=""> <a class="remove" href="javascript:void(0)" data-action="wizard[order][domains][remove_domain]"></a> <div class="preview"> <span></span> <span></span> </div></div>';

	body.find('.domain_collection').append(newDomainRow);

	processAllDomains();

});

body.on('click', '[data-action="wizard[order][domains][remove_domain]"]', function() {
	$(this).closest('.domain').remove();

	processAllDomains();

});


function processAllDomains() {

	// process all domains
	body.find('[name="wizard[order][domains][domain]"]').each(function() {
	processDomainsToProtect($(this));
	});

}


/* WIZARDS - OPEN & CLOSE STEPS */
body.on('click', 'ul.steps > li:not(.open)', function(event) {
    const element = this;

	// no action at all for permanently locked steps
	if ($(element).hasClass('locked_permanently')) {
	return false;
	}

	// remove all alerts
	generalInfo('hide');

	// validate current step and potentially mark completed
	var currentOpenStep = body.find('li.step.open');
	var currentOpenStepID = body.find('li.step.open').attr('data-step-id');

	wizardValidateStep(currentOpenStepID, 'disableAlerts').then(function(valid) {
        if (valid && !currentOpenStep.hasClass('finalize') /*&& !$(element).hasClass('locked')*/) {
            currentOpenStep.addClass('complete');
        }

        wizardLockUnlockSteps();

        // no further action for locked steps
        if ($(element).hasClass('locked')) {
            return false;
        }

        // then open clicked step
        body.find('ul.steps > li').removeClass('open');
        $(element).addClass('open');

        // auto-select plan
        wizardPreselectPlan();
    });
});


/* WIZARDS - OPEN & CLOSE STEPS */
body.on('click', '[data-action="wizard[next_step]"]', function() {

	var button = $(this);
	var thisStepID = $(this).closest('li.step').attr('data-step-id');

	const wizardElement = this;
    wizardValidateStep(thisStepID).then(function(validStep) {
        // if step finished
        if (validStep) {

            // if not finalize step, auto-select plan
            if (!$(wizardElement).closest('li.step').hasClass('finalize')) {
                wizardPreselectPlan();
            }

            // mark step completed
            $(wizardElement).closest('li.step').removeClass('open').addClass('complete');

            // if unfinished steps left
            if (body.find('li.step:not(.complete)').length > 0) {

                // open next unfinished step
                var index = 0;

                body.find('li.step:not(.complete):not(.locked_permanently)').each(function() {

                    index ++;

                    // skip all results except first
                    if (index != 1) {
                        return true;
                    }

                    // if locked field, force-unlock it
                    if ($(this).hasClass('locked')) {
                        $(this).removeClass('locked');
                    }

                    $(this).addClass('open');
                });

            } else {

                // show loading
                button.addClass('loading');

                // make sure last "finalize your order" step stays open
                body.find('li.step.finalize').removeClass('complete').addClass('open');

                var freePlanID = body.find('.plan.free [name="wizard[order][plan][id]"]').val();
                var selectedPlan = body.find('[name="wizard[order][plan][selected]"]').val();

                // if selected plan is free plan or selected plan is current plan, submit right away
                if ((selectedPlan === freePlanID) || body.find('[name="wizard[order][plan][id]"][value="'+selectedPlan+'"]').closest('.plan').find('[name="wizard[order][plan][is_current_subscription]"]').val()) {
                    submitOrderWizard();
                    return false;
                }

                var	postData = {
                    plan_id: selectedPlan,
                    payment_frequency: body.find('[name="user[payment_frequency]"]').val(),
                };

                var postDataJSON = JSON.stringify(postData);
                //console.log(postDataJSON);

                $.ajax({
                    type: 'POST',
                    url: '/ajax/advanced_ajax_handler.php?type=change_subscription_plan&_cpt=' + getCookie('_cpt'),
                    data: ({ postArray: postDataJSON }),
                    dataType: "json",
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        //alert(textStatus + ', ' + errorThrown);
                    },
                    success: function(data){

                        button.removeClass('loading');

                        if (data.success === 1) {

                            if (data.message.payment_required == 1 && data.message.invoice_id) {

                                var	customData = {
                                    invoice_id: data.message.invoice_id
                                };

                                openPopup('checkout_via_popup', customData);

                            }

                            return false;

                        }  else {

                            generalInfo('show', 'error', translateError(data.message));
                            return false;

                        }

                    }

                });

            }


        } else {

            // mark step unfinished
            $(wizardElement).closest('li.step').removeClass('complete');

            wizardLockUnlockSteps();

        }
    });
});


/* WIZARDS - VALIDATE STEP */
function wizardValidateStep(stepID, command) {

	generalInfo('hide');

	switch (stepID) {
        case 'wizard[order][csr]':
            if(body.find('[name="wizard[order][csr][paste_csr]"]').is(':checked')) {
                const certificateCSR = body.find('[name="wizard[order][csr][paste_csr_content]"]').val();

                return $.Deferred(function (defer) {
                    const postDataJSON = JSON.stringify({csr: certificateCSR});
                    $.ajax({
                        type: "POST",
                        url: '/ajax/advanced_ajax_handler.php?type=zerossl_validate_csr',
                        data: ({ postArray: postDataJSON}),
                        dataType: "json",
                        error: function(XMLHttpRequest, textStatus, errorThrown) {
                            //alert(textStatus + ', ' + errorThrown);
                            console.log(textStatus, errorThrown);
                            defer.resolve(true);
                        },
                        success: function(data){
                            if (data.success === 1) {
                                defer.resolve(true);
                            }  else {
                                if (command !== 'disableAlerts') {
                                    generalInfo('show', 'error', "There is a problem with your CSR: " + data.message);
                                }
                                defer.resolve(false);
                            }
                        }
                    })
                });
            }
            break;

		case 'wizard[order][domains]':

			var validDomains = 0;

			body.find('.domain_collection .domain').each(function() {

				// if no domain or invalid domain provided, error
				if ($(this).find('[name="wizard[order][domains][domain][submit_value]"]').val() && isValidDomain($(this).find('[name="wizard[order][domains][domain][submit_value]"]').val())) {

				validDomains ++;

				}

			});

			if (validDomains < 1) {

				if (command !== 'disableAlerts') {
				generalInfo('show', 'error', 'Error: You have not specified a valid domain name.');
				}

			return $.Deferred().resolve(false);
			}

		break;

		case 'wizard[install][download_install]':

			if (!body.find('li.step.finalize').hasClass('complete')) {
                return $.Deferred().resolve(false);
			}

		break;


	}

	return $.Deferred().resolve(true);

}


/* WIZARDS - UNLOCK STEPS */
function wizardLockUnlockSteps() {

	// if there are no regular (non-locked, non-exit) steps left uncompleted
	if (body.find('li.step:not(.complete):not(.locked)').length < 1) {

		// unlock one of the locked fields
		body.find('ul.steps li.step.locked:first').removeClass('locked');

	} else {

		// else lock all lockable fields
		body.find('ul.steps li.step.is_lockable').addClass('locked').removeClass('complete').removeClass('open');

	}

}


/* ORDER - SWITCH AUTO CSR */
body.on('change', '[name="wizard[order][csr][auto]"]', function() {

	if ($(this).is(':checked')) {

		body.find('.custom_csr').hide();

	} else {

		body.find('.custom_csr').show();

	}

});


/* ORDER - SWITCH PASTE CSR */
body.on('change', '[name="wizard[order][csr][paste_csr]"]', function() {

	if ($(this).is(':checked')) {

		body.find('.paste').show();
		body.find('.enter').hide();

	} else {

		body.find('.paste').hide();
		body.find('.enter').show();

	}

});


/* ORDER - SWITCH PASTE SAME TECH CONTACT */
body.on('change', '[name="wizard[order][csr][custom_tech_same_as_admin]"]', function() {

	if ($(this).is(':checked')) {

		body.find('.form_row.tech_contact .form_row:not(.checkbox)').hide();

	} else {

		body.find('.form_row.tech_contact .form_row:not(.checkbox)').show();

	}

});


/* ORDER - PRE-SELECT PLAN - FREE USER FLOW ONLY */
function wizardPreselectPlan(returnSelectedFeatures) {

	// store usage stats
	var currentStatsUsed90d = parseInt(body.find('[name="user[stats][used_90day_certificates]"]').val());
	var currentStatsUsed90dWildcards = parseInt(body.find('[name="user[stats][used_90day_wildcard_certificates]"]').val());
	var currentStatsUsed90dMultiDomain = parseInt(body.find('[name="user[stats][used_90day_multi_domain_certificates]"]').val());
	var currentStatsUsed1y = parseInt(body.find('[name="user[stats][used_1_year_certificates]"]').val());
	var currentStatsUsed1yWildcards = parseInt(body.find('[name="user[stats][used_1_year_wildcard_certificates]"]').val());

	// check if the current plan is an official plan
	var isCurrentPlanOfficial = body.find('[name="wizard[order][plan][is_current_plan_official]"]').val() === 'true';

	// this array is used for select-lower-plan-popup
	// this is filled sporadically across the functions below
	var selectedFeatures = [];

	// number of domains, wildcard
	var factorNumberOfDomains;
	var factorWildcard = false;

	// check if wildcard by wildcard checkbox as well as by form class "is_wildcard"
	if (body.find('[name="wizard[order][domains][wildcard]"]').is(':checked') || body.find('form[name="wizard[order][domains]"]').hasClass('is_wildcard')) {

		factorNumberOfDomains = 1;
		factorWildcard = true;

	} else {

		factorNumberOfDomains = 0;

		body.find('[name="wizard[order][domains][domain][submit_value]"]').each(function() {

			if ($(this).val()) {
			factorNumberOfDomains ++;
			}

		});

	}

	// fill selectedFeatures
	if (factorNumberOfDomains > 1) {
	selectedFeatures.push({'key': 2, 'value': 'Multi-Domain (' + factorNumberOfDomains + ' Domains)'});
	}

	// validity
	var factorValidity;

	factorValidity = parseInt(body.find('[name="wizard[order][validity]"]:checked').val());

	// add-ons
	var factorAddons = [];

	body.find('[name="wizard[order][addons]"] .form_row.checkbox').each(function() {

		if ($(this).find('input[type="checkbox"]').is(':checked')) {
		factorAddons.push($(this).find('input[type="checkbox"]').val());

		// fill selectedFeatures
		selectedFeatures.push({'key': 3, 'value': 'Add-On: ' + $(this).find('label span').text()});

		}

	});

	//console.log('--- NEW LINE ---');
	//console.log('factorNumberOfDomains = ' + factorNumberOfDomains);
	//console.log('factorWildcard = ' + factorWildcard);
	//console.log('factorValidity = ' + factorValidity);
	//console.log('factorAddons = ' + factorAddons);

	var planToSelect = 'none';

	if (factorWildcard === true) {

		// wildcards supported on premium plan
		planToSelect = 'premium';

		// 1-year wildcards are restricted
		if (factorValidity === 365) {

			if (currentStatsUsed1yWildcards >= 1) {
			planToSelect = 'business';
			}

			if (currentStatsUsed1yWildcards >= 3) {
			planToSelect = 'business_40';
			}

			if (currentStatsUsed1yWildcards >= 5) {
			planToSelect = 'business_75';
			}

			if (currentStatsUsed1yWildcards >= 10) {
			planToSelect = 'business_100';
			}

			if (currentStatsUsed1yWildcards >= 15) {
			planToSelect = 'business_150';
			}

			if (currentStatsUsed1yWildcards >= 25) {
			planToSelect = 'business_150';
			generalInfo('show', 'info', 'It looks like you currently have more than 25x 1-year wildcard certificates on your account, which is the maximum we offer using this website. To get more credits, please <a target="_blank" href="https://zerossl.com/contact/quote">contact our team</a> for a quote.');
			}

		}

	}

	if (factorWildcard !== true && factorValidity === 365) {

		if (factorNumberOfDomains >= 1) {

			// 1-year certs for up to 3 domains = basic plan
			planToSelect = 'basic';

			if ((factorNumberOfDomains + currentStatsUsed1y) > 3) {
			planToSelect = 'premium';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 10) {
			planToSelect = 'business';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 25) {
			planToSelect = 'business_40';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 40) {
			planToSelect = 'business_75';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 75) {
			planToSelect = 'business_100';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 100) {
			planToSelect = 'business_150';
			}

			if ((factorNumberOfDomains + currentStatsUsed1y) > 150) {
			planToSelect = 'business_150';
			}

		}

	}

	if (factorWildcard !== true && factorValidity === 90) {

		// multi-domain and add-ons not supported on free plan,
		if (factorNumberOfDomains > 1 || factorAddons.length > 0) {
		planToSelect = 'basic';
		} else if (currentStatsUsed90d >= 3){
		// if user already has 3 or more 90-day certs, upgrade to basic
		planToSelect = 'basic';
		} else {
		// otherwise free plan
		planToSelect = 'free';
		}

	}

	if (!isCurrentPlanOfficial) {
		planToSelect = 'none';
	}

	//console.log('AUTO-SELECT PLAN = ' + planToSelect);

	// generate dynamic summary
	var dynamicSummary = 'Based on your selection of a <strong>';

	if (factorValidity == 365) {

		dynamicSummary += '1-Year ';

		// fill selectedFeatures
		selectedFeatures.push({'key': 1, 'value': '1-Year Certificate'});

	} else {

		dynamicSummary += '90-Day ';

		// fill selectedFeatures
		selectedFeatures.push({'key': 1, 'value': '90-Day Certificate'});

	}

	if (factorWildcard == true) {

		dynamicSummary += 'Wildcard SSL Certificate</strong> ';

		// fill selectedFeatures
		selectedFeatures.push({'key': 2, 'value': 'Wildcard'});

	} else if (factorNumberOfDomains > 1) {

		var domainCountContent;

		// show credit explanation tooltip for 1-year certs
		if (factorValidity == 365) {
		domainCountContent = '<i class="domains_credits_tooltip" data-tooltip="Each domain protected in your 1-Year SSL Certificate will consume one credit from your account.">'+factorNumberOfDomains+' Domains</i>';
		} else {
		domainCountContent = factorNumberOfDomains+' Domains';
		}

		dynamicSummary += 'Multi-Domain SSL Certificate ('+domainCountContent+')</strong> ';

	} else {

		dynamicSummary += 'SSL Certificate</strong> ';

	}

	if (factorAddons.length > 0) {

		var singularPlural;

		if (factorAddons.length > 1) {
		singularPlural = 'Add-Ons';
		} else {
		singularPlural = 'Add-On';
		}

		dynamicSummary += 'and <strong>'+factorAddons.length+' '+singularPlural+'</strong> ';

	}

	//console.log(planToSelect);

	// if free plan, or if auto-selected plan is current plan (only for paid users), or if auto-selected plan does not exist on page (only for paid users)
	if (planToSelect === 'free' || body.find('.plans .plan[data-plan-identification="'+planToSelect+'"] [name="wizard[order][plan][is_current_subscription]"]').val() || body.find('.plans .plan[data-plan-identification="'+planToSelect+'"]').length < 1) {
	dynamicSummary += 'you are fine staying on the ';
	} else {
	dynamicSummary += 'you will need the ';
	}

	var displayPlanName;

	// if detected plan exists on page, add it to summary
	if (body.find('.plans .plan[data-plan-identification="'+planToSelect+'"]').length) {
	displayPlanName = body.find('.plans .plan[data-plan-identification="'+planToSelect+'"] .top_section span').text();
	} else {
	// else add current plan to summary
	displayPlanName = body.find('[name="wizard[order][plan][is_current_subscription]"]').closest('.plan').find('.top_section span').text();
	}

	dynamicSummary += '<strong>' + displayPlanName + ' Plan</strong>.';

	// if only features should be returned, stop function here
	if (returnSelectedFeatures === true) {
	return selectedFeatures;
	}

	// show dynamic summary
	body.find('[data-dynamic-summary="true"]').html(dynamicSummary);

	//console.log('original planToSelect = ' + planToSelect);

	var autoSelectPlanID;

	// if detected plan exists on page, auto-select it
	if (body.find('.plans .plan[data-plan-identification="'+planToSelect+'"]').length) {

		// auto-select plan
		body.find('.plans .plan').removeClass('selected');
		body.find('.plans .plan[data-plan-identification="'+planToSelect+'"]').addClass('selected');

		// fill plan id in hidden inputs
		autoSelectPlanID = body.find('.plans .plan.' + planToSelect + ' input[name="wizard[order][plan][id]"]').val();

		body.find('[name="wizard[order][plan][auto_selected]"]').val(autoSelectPlanID);
		body.find('[name="wizard[order][plan][selected]"]').val(autoSelectPlanID);

	} else {
	// else keep current subscription plan selected

		planToSelect = body.find('[name="wizard[order][plan][is_current_subscription]"]').closest('.plan').attr('data-plan-identification');

		//console.log('overriden planToSelect = ' + planToSelect);

		// auto-select plan
		body.find('.plans .plan').removeClass('selected');
		body.find('.plans .plan[data-plan-identification="'+planToSelect+'"]').addClass('selected');

		autoSelectPlanID = body.find('[name="wizard[order][plan][is_current_subscription]"]').closest('.plan').find('input[name="wizard[order][plan][id]"]').val();

		body.find('[name="wizard[order][plan][selected]"]').val(autoSelectPlanID);
		body.find('[name="wizard[order][plan][auto_selected]"]').val('');

	}

}


/* ORDER - SELECT PLAN */
body.on('click', '[data-action="wizard[order][select_plan]"]', function() {
	var autoSelectedPlan = parseInt(body.find('[name="wizard[order][plan][auto_selected]"]').val());

	var currentSelectedPlan = parseInt(body.find('[name="wizard[order][plan][selected]"]').val());
	var 	currentSelectedPlanName = body.find('[name="wizard[order][plan][id]"][value="'+currentSelectedPlan+'"]').closest('.plan').find('.top_section span').text();

	var clickedPlan = parseInt($(this).attr('data-action-id'));
	var targetPlanName = $(this).closest('.plan').find('.top_section span').text();

	// get current usage stats from hidden inputs
	var currentStatsUsed90d = body.find('[name="user[stats][used_90day_certificates]"]').val();
	var currentStatsUsed90dWildcards = body.find('[name="user[stats][used_90day_wildcard_certificates]"]').val();
	var currentStatsUsed90dMultiDomain = body.find('[name="user[stats][used_90day_multi_domain_certificates]"]').val();
	var currentStatsUsed1y = body.find('[name="user[stats][used_1_year_certificates]"]').val();
	var currentStatsUsed1yWildcards = body.find('[name="user[stats][used_1_year_wildcard_certificates]"]').val();

	// get current plan limits from hidden inputs
	var currentPlanLimit90d = body.find('[name="user[stats][allowed_90day_certificates]"]').val();
	var currentPlanLimit90dWildcards = body.find('[name="user[stats][allowed_90day_wildcard_certificates]"]').val();
	var currentPlanLimit90dMultiDomain = body.find('[name="user[stats][allowed_90day_multi_domain_certificates]"]').val();
	var currentPlanLimit1y = body.find('[name="user[stats][allowed_1_year_certificates]"]').val();
	var currentPlanLimit1yWildcards = body.find('[name="user[stats][allowed_1_year_wildcard_certificates]"]').val();

	// edge case: if user on free plan and used all 90-day certs
	if (targetPlanName === 'Free' && (currentStatsUsed90d >= currentPlanLimit90d)) {
	return false;
	}

	// if lower plan is selected, show warning popup
	// TODO: checking plan id via "x < y" is not a long-term solution here
	if (clickedPlan < autoSelectedPlan) {

		// get target plan name
		var targetPlanFeaturesHTML = body.find('[name="wizard[order][plan][id]"][value="'+clickedPlan+'"]').closest('.plan').find('.features').html();

		var currentUsageStats = 	{
			current_stats_used_90d: currentStatsUsed90d,
			current_stats_used_90d_wildcards: currentStatsUsed90dWildcards,
			current_stats_used_90d_multi_domain: currentStatsUsed90dMultiDomain,
			current_stats_used_1y: currentStatsUsed1y,
			current_stats_used_1y_wildcards: currentStatsUsed1yWildcards,
		}

		var currentPlanLimits = 	{
			current_plan_limit_90d: currentPlanLimit90d,
			current_plan_limit_90d_wildcards: currentPlanLimit90dWildcards,
			current_plan_limit_90d_multi_domain: currentPlanLimit90dMultiDomain,
			current_plan_limit_1y: currentPlanLimit1y,
			current_plan_limit_1y_wildcards: currentPlanLimit1yWildcards,
		}

		// build POST array
		var	customData = {
			current_usage_stats: currentUsageStats,
			current_plan_limits: currentPlanLimits,
			wizard_selected_features: wizardPreselectPlan(true),
			current_selected_plan_name: currentSelectedPlanName,
			target_plan_features: targetPlanFeaturesHTML,
			target_plan_name: targetPlanName,
		};

		openPopup('confirm_wizard_plan_selection', customData);

		return false;

	}

	// change plan
	body.find('.plans .plan').removeClass('selected');
	$(this).closest('.plan').addClass('selected');

	body.find('[name="wizard[order][plan][selected]"]').val(clickedPlan);

});


/* ORDER - SUBMIT WIZARD */
function submitOrderWizard() {

	// domains & common name
	let certificateDomains = [];
	let certificateCommonName;

    let strict_domains_selector = "wizard[order][domains][domain]strict_domains"
    let strict_domains_element = body.find(`[name="${strict_domains_selector}"]`);
    let strict_domains_value = strict_domains_element.val() !== "false"
    let wwwonly = strict_domains_element.attr("data-wwwonly") === "true";

	body.find('[name="wizard[order][domains][domain][submit_value]"]').each(function(index) {

		if ($(this).val()) {
			certificateDomains.push($(this).val());

			if (index === 0) {
                certificateCommonName = $(this).val();
			}

		}
	});

	// ZERO-157
	// if no auto sugestion with WWW is present || shown in UI, then we send {"strict_domains": true} to the backend
	const hadPreviewWithWWW = $('.preview-with-www').length === 0;
	const hiddenPreviewWithWWW = $('.preview-with-www').css("display") === "none";

	if (hadPreviewWithWWW || hiddenPreviewWithWWW) {
		strict_domains_value = true;
	}

    if(certificateDomains.length === 1 && strict_domains_value && wwwonly) {
        certificateCommonName = certificateDomains[0] = "www." + certificateDomains[0];
    }

    certificateDomains = certificateDomains.join(',');

    // validity
	let certificateValidityDays = parseInt(body.find('[name="wizard[order][validity]"]:checked').val());

	// CSR & private key (key pair)
	let certificatePKEncrypted;
	let certificateCSR;

	// pasted CSR, no need to generate key pair
	if (!body.find('[name="wizard[order][csr][auto]"]').is(':checked') && body.find('[name="wizard[order][csr][paste_csr]"]').is(':checked')) {

		certificateCSR = body.find('[name="wizard[order][csr][paste_csr_content]"]').val();

	} else {
	// we need to generate key pair

		let csrOrganization = body.find('[name="wizard[order][csr][custom_organization]"]').val();
        let csrOrganizationUnitName = body.find('[name="wizard[order][csr][custom_department]"]').val();
        let csrLocality = body.find('[name="wizard[order][csr][custom_city]"]').val();
        let csrState = body.find('[name="wizard[order][csr][custom_state]"]').val();
        let csrCountry = body.find('[name="wizard[order][csr][custom_country]"]').val();
        let csrEmail = body.find('[name="wizard[order][csr][custom_email]"]').val();

		// generate and store key pair
        let certificateKeyPair = generateKeyPair([certificateCommonName, csrOrganization, csrOrganizationUnitName, csrLocality, csrState, csrCountry, csrEmail]);

		// store csr and encrypted private key
		certificateCSR = certificateKeyPair['csr'];
		certificatePKEncrypted = certificateKeyPair['privateKeyEncrypted'];

		//console.log(certificateCSR);

	}

	let	postData = {
		strict_domains: strict_domains_value,
		certificate_domains: certificateDomains,
		certificate_validity_days: certificateValidityDays,
		certificate_csr: certificateCSR,
		certificate_pk_encrypted: certificatePKEncrypted,
	};

	let postDataJSON = JSON.stringify(postData);
	// console.log(postDataJSON);

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_create_certificate&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			if (data.success === 1) {

				closePopup();

				goToPage('/certificate/verify/'+data.message.id, 'verify', 'verify', null, data.message.id, false, ['show', 'success', 'Your certificate has been created and is ready for domain verification.'], null);

			}  else {

				// stop any loading, both popup and non-popup
				body.find('.loading').removeClass('loading');

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

}

body.on('click', '.subscriptions .plans_page', function() {

	if ($(this).hasClass('disabled')) {
	return false;
	}

	$(this).closest('.plans').toggleClass('page_2');

	$(this).addClass('disabled');
	body.find('.plans_page').not($(this)).removeClass('disabled');

	if ($(this).hasClass('next')) {
	body.find('.plan:not(.page_2)').hide();
	body.find('.plan.page_2').fadeIn(100).css("display","inline-block");
	} else {
	body.find('.plan.page_2').hide();
	body.find('.plan:not(.page_2)').fadeIn(100).css("display","inline-block");
	}

});



/* ORDER - CONFIRM PLAN SELECTION POPUP - ADJUST CERTIFICATE BUTTON */
body.on('click', '[data-action="wizard_adjust_certificate"]', function() {

	body.find('li.step').removeClass('open');
	body.find('li.step[data-step-id="wizard[order][domains]"]').addClass('open');

	closePopup();

});



/* GENERATE FILE + DOWNLOAD USING JS */
var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName, fileType) {
        var content = data,
            blob = new Blob([content], {type: '"' + fileType + '"'}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());



/* VALIDATE - DOWNLOAD AUTH FILE */
body.on('click', '[data-action="download_auth_file"]', function(event) {

	event.preventDefault();

	// store contents, generate array and insert line breaks
	var fileContentArray = $(this).attr('data-file-content').split(',');
	var fileContentFinal = fileContentArray[0] + '\n' + fileContentArray[1] + '\n' + fileContentArray[2];

	var fileName = $(this).attr('data-file-name');

	// download txt file
	saveData(fileContentFinal, fileName, 'text/plain');

});



/* VALIDATE - SWITCH BETWEEN VALIDATION METHODS */
body.on('change', '[name="wizard[validate][method]"]', function(event) {

	// changing validation methods will mark all domains as non-completed
	body.find('li.step').removeClass('complete');

	var chosenMethod = body.find('[name="wizard[validate][method]"]:checked').attr('data-method-id');

	// handle verification boxes show/hide
	body.find('li:not(.open) [data-validation-method]').hide();
	body.find('li:not(.open) [data-validation-method="'+chosenMethod+'"]').show();
	body.find('li:not(.open) [data-validation-method="'+chosenMethod+'"] input[type="radio"]').prop('checked', true);

	// handle verification summary in last step
	updateVerificationSummary();

});



/* VALIDATE - UPDATE VERIFICATION SUMMARY CHOSEN EMAIL ON CHANGE OF EMAIL SELECT */
body.on('change', '[name="wizard[validate][method][email][selected_email]"]', function(event) {

	updateVerificationSummary();

});


/* VALIDATE - UPDATE VERIFICATION SUMMARY CHOSEN EMAIL */
function updateVerificationSummary() {

	body.find('[data-verification-summary]').each(function() {

		var chosenMethod = body.find('[name="wizard[validate][method]"]:checked').attr('data-method-id');
		var methodContent;

		var thisDomain = $(this).attr('data-verification-summary');
		var chosenEmailForThisDomain = body.find('[data-domain="'+thisDomain+'"] [name="wizard[validate][method][email][selected_email]"]').val();

		const fileUploadType = body.find('[name="file_upload_type"]:checked').val().toUpperCase();

		switch (chosenMethod) {

			case 'wizard[validate][method][email]':
			methodContent = '<span class="custom" data-tooltip="Send to: '+chosenEmailForThisDomain+'">Email Verification</span>';
			break;

			case 'wizard[validate][method][cname]':
			methodContent = 'DNS (CNAME)';
			break;

			case 'wizard[validate][method][file]':
			methodContent = `${fileUploadType} File Upload`;
			break;

		}

		// add method content
		$(this).find('[data-summary-item="method"]').html(methodContent);

		// reset all statuses to default
		$(this).find('[data-summary-item="status"]').attr('class', 'status');
		$(this).find('[data-summary-item="status"] span').text('To start, click "Verify Domains"');

	});

}


/* VALIDATE - CANCEL AND START NEW */
body.on('click', '[data-action="wizard[validate][start_new]"]', function(event) {

	event.preventDefault();

	goToPage('/certificate/verify/'+currentID, 'verify', 'verify', null, currentID, false, ['show', 'info', 'You can now start fresh verifying your domains. Need help? <a target="_blank" href="https://help.zerossl.com/hc/en-us/articles/360058295354-Verify-Domains">Read this article</a> to learn about domain verification.'], null);

});

function getCaaError(data) {
	if (!data) {
		return;
	}
	let domainLabel = data.message.details.length === 1 ? "domain is" : "domains are";
	let domainListItems = "";
	$.each(data.message.details, function(domain) {
		domainListItems += `<li>${data.message.details[domain]}</li>`
	});

	return `It appears that the CAA records for the following ${domainLabel} not configured to allow us to issue SSL certificates.
		<ul>
			${domainListItems}
		</ul>
		<p>To resolve this issue:</p>
		<ul>
			<li>Remove all existing CAA records from your domain's DNS settings or</li>
			<li>Add a CAA record to your domain's DNS with sectigo.com (ZeroSSL\'s root CA) as the authorized certificate authority.</li>
		</ul>
		<p>
			Please update your DNS settings and try again. If you need further assistance, visit our 
			<a href="https://help.zerossl.com/hc/en-us/articles/360060119753-Invalid-CAA-Records" target="_blank">Help Center</a>.
		</p>
	`;
}


/* VALIDATE - SUBMIT WIZARD */
function submitValidateWizard() {

	generalInfo('hide');

	var button = body.find('[data-action="wizard[validate][submit]"]');
	button.addClass('loading');

 	// cert hash
	var certificateHash = currentID;

	// selected verification method
	var selectedMethod = body.find('[data-step-id="wizard[validate][domain]"]:first [name="wizard[validate][method]"]:checked').attr('data-method-id');
	var submitMethod;

	// Get the type of file upload (http/https)
	const fileUploadType = body.find('[name="file_upload_type"]:checked').val();

	switch (selectedMethod) {

		case 'wizard[validate][method][email]':
		submitMethod = 'EMAIL';
		break;

		case 'wizard[validate][method][cname]':
		submitMethod = 'CNAME_CSR_HASH';
		break;

		case 'wizard[validate][method][file]':
		submitMethod = fileUploadType === 'https' ? 'HTTPS_CSR_HASH' : 'HTTP_CSR_HASH';
		break;

	}

	// selected verification emails
	var arrayVerificationEmails = [];
	var submitVerificationEmails;

	if (selectedMethod === 'wizard[validate][method][email]') {

		body.find('[name="wizard[validate][method][email][selected_email]"]').each(function() {
		arrayVerificationEmails.push($(this).val());
		});

		submitVerificationEmails = arrayVerificationEmails.join(',');

	}

	var	postData = {
		id: certificateHash,
		validation_method: submitMethod,
		validation_email: submitVerificationEmails,
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_validate_certificate',
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			if (data.success === 1) {

				// lock domain steps permanently
				body.find('[data-step-id="wizard[validate][domain]"]').addClass('locked_permanently');

				switch (submitMethod) {

					case 'EMAIL':

						goToPage('/certificate/verify/'+currentID+'/status', 'verify', 'verify', 'status', currentID, false, ['show', 'info', 'An email with a verification link has been sent for each of the domains in your certificate.', 'li.step.finalize .alerts'], null);

					break;

					case 'CNAME_CSR_HASH':
					case 'HTTP_CSR_HASH':
					case 'HTTPS_CSR_HASH':

						generalInfo('show', 'success', 'Redirecting ...');

						goToPage('/certificate/install/'+currentID, 'install', 'install', '', currentID, false, ['show', 'info', 'Congratulations, your domains have been verified. This means that our system is issuing your certificate at the moment. This page will refresh automatically every few seconds.'], null);

					break;

				}

			} else {

				button.removeClass('loading');

				var partialSuccessCount = 0;
				var isCaaError;

				if (data.message.details) {

					// check for partial success
					$.each(data.message.details, function(domain) {

						// mark domains verified
						if (data.message.details[domain].validation_successful == true) {

							partialSuccessCount ++;

							// mark domain verified
							body.find('[data-verification-summary="'+domain+'"] [data-summary-item="status"]').attr('class', 'status validation_complete');
							body.find('[data-verification-summary="'+domain+'"] [data-summary-item="status"] span').text('Verified');

						} else {
							// check for CAA error
							if (data.message.type === 'invalid_caa_records_detected') {

								isCaaError = true;

								body.find('[data-verification-summary="'+data.message.details[domain]+'"] [data-summary-item="status"]').attr('class', 'status failed');
								body.find('[data-verification-summary="'+data.message.details[domain]+'"] [data-summary-item="status"] span').text('Invalid CAA Records');

								return;

							}

							// check for partial success in sub-folders of response
							$.each(data.message.details[domain], function(domainSubFolder) {

                                let validationResultDetails = data.message.details[domain][domainSubFolder];

								if (!!validationResultDetails["validation_successful"]) {
                                    // if contains www, strip this away and simply mark non-www version completed
                                    if (domainSubFolder.indexOf('www.') >= 0) {
                                        domainSubFolder = domainSubFolder.replace(/www./, '');
                                    }

                                    partialSuccessCount++;

                                    // mark domain verified
                                    body.find('[data-verification-summary="' + domain + '"] [data-summary-item="status"]').attr('class', 'status validation_complete');
                                    body.find('[data-verification-summary="' + domain + '"] [data-summary-item="status"] span').text('Verified');

								} else {
								    // in case of failure
                                    let message = "";
                                    let messageDetails = validationResultDetails["error_info"] ??
                                        "An unknown error has occurred. Check status.zerossl.com and try again later. Contact our support team if the problem persists.";
                                    switch (validationResultDetails["error_slug"]) {
                                        case 'http_transport_failed':
                                            message = "HTTP transport error";
                                            break;
                                        case 'bad_response_code':
                                            message = "Bad response code";
                                            break;
                                        case 'timeout':
                                            message = "Timeout";
                                            break;
                                        case 'bad_file_content':
                                            message = "Bad file content";
                                            break;
                                        case 'wrong_file_content':
                                            message = "Wrong file content";
                                            break;
                                        default:
                                            message = "Unknown error";
                                            break;
                                    }

                                    body.find('[data-verification-summary="'+domain+'"] [data-summary-item="status"]').attr('class', 'status failed');
									body.find('[data-verification-summary="'+domain+'"] [data-summary-item="status"] span').html(escapeHtml(message) + ' <i data-tooltip="' + escapeHtml(messageDetails) + '"></i>');
                                }
							});
						}
					});
				}

				var errorMessageText;

				switch (submitMethod) {

					case 'EMAIL':

						if (isCaaError === true) {
							errorMessageText = getCaaError(data);
						} else {
						// if email verification cannot be initiated, simply go to status status page
						// would show current verification status if cert status is already pending_validation
						// if cert status is still draft, user will simply retart validation on the target page
						goToPage('/certificate/verify/'+currentID+'/status', 'verify', 'verify', 'status', currentID, false, null, null);
						return false;
						}

					break;

					case 'CNAME_CSR_HASH':

						var plural = partialSuccessCount > 1 ? 'entries' : 'entry';

						if (partialSuccessCount > 0) {
						    errorMessageText = 'We were able to verify '+partialSuccessCount+' CNAME '+plural+', but not all of them. Please check for errors and try again.'
						} else {
							if (isCaaError) {
								errorMessageText = getCaaError(data);
							} else {
								errorMessageText = 'We were unable to verify your CNAME entry. Please check for errors on your side and try again in 5-10 minutes.';
							}
						}

					break;

					case 'HTTP_CSR_HASH':
					case 'HTTPS_CSR_HASH':

						var plural = partialSuccessCount > 1 ? 'files' : 'file';

						if (partialSuccessCount > 0) {
						    errorMessageText = 'We were able to verify '+partialSuccessCount+' uploaded '+plural+', but not all of them. Please check for errors and try again.'
						} else {
							if (isCaaError) {
								errorMessageText = getCaaError(data);
							} else {
								errorMessageText = 'We were unable to verify your uploaded file. Please check for errors on your side and try again after 5-10 minutes.'
							}
						}

					break;

				}

				generalInfo('show', 'error', errorMessageText, 'li.step.finalize .alerts');
				return false;

			}

		}

	});

}


/* VALIDATE - TRIGGER SUBMISSION */
body.on('click', '[data-action="wizard[validate][submit]"]', function(event) {

	event.preventDefault();

	// submit validation
	submitValidateWizard();

});


/* VALIDATE - RESEND VERIFICATION EMAIL */
body.on('click', '[data-action="wizard[validate][resend_email]"]', function(event) {

	var button = $(this);
	button.addClass('loading');

	var certHash = currentID;

	var	postData = {
		id: certHash
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_resend_validation_email',
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			button.removeClass('loading');

			if (data.success === 1) {

				generalInfo('show', 'success', 'Your verification email has been resent. Trouble receiving it? <a target="_blank" href="https://help.zerossl.com/hc/en-us/articles/360060120053-Email-Verification-Troubleshooting">Reading this article</a> could help resolve the issue.', 'li.step.finalize .alerts');

			}  else {

				generalInfo('show', 'error', translateError(data.message), 'li.step.finalize .alerts');
				return false;

			}

		}

	});

});


/* VALIDATE - REFRESH STATUS */
body.on('click', '[data-action="wizard[validate][refresh_validation_status]"]', function(event) {

	var button = $(this);
	button.addClass('loading');

	reloadPage();

});


/* INSTALL - DOWNLOAD CERT */
body.on('click', '[data-action="wizard[install][download_certificate]"]', function(event) {

	var button = $(this);
	button.addClass('loading');

	var certHash;

	if ($(this).attr('data-action-id')) {
	certHash = $(this).attr('data-action-id');
	} else {
	certHash = currentID;
	}

	var certCommonName = $(this).attr('data-action-filename');

	var	postData = {
		id: certHash
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_download_raw_certificate&_cpt=' + getCookie('_cpt'),
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			button.removeClass('loading');

			if (data.success === 1) {

				// store certificate files
				var certificate = data.message['certificate.crt'];
				var certificateCaBundle = data.message['ca_bundle.crt'];

				// handle encrypted private key and decrypt it
				var encryptedPrivateKey;
				var decryptedPrivateKey;
				var includePrivatekey = false;

				// if there is an encrypted private key returned from server
				if (data.message['private.key']) {

					// try decrypting private key
                    try {

						// include private key in ZIP
						includePrivatekey = true;

						// store encrypted private key
						encryptedPrivateKey = data.message['private.key'];

						// decrypt encrypted private key
						decryptedPrivateKey = decryptPrivateKey(encryptedPrivateKey);

						// do not include private key in ZIP if decrypted private key is invalid
						if (decryptedPrivateKey.indexOf('BEGIN RSA PRIVATE KEY') < 1) {
						includePrivatekey = false;
						}

					// if decryption does not work, do not include private key
                    } catch(error) {

                        console.log(error);
                        includePrivatekey = false;

                    }

				}

				// generate ZIP from certificate files and private key
				var zip = new JSZip();
				zip.file('certificate.crt', certificate);
				zip.file('ca_bundle.crt', certificateCaBundle);

				// include private key only if it is returned from server
				if (includePrivatekey === true) {
				zip.file('private.key', decryptedPrivateKey);
				}

				zip.generateAsync({type:"blob"})
				.then(function(content) {

					// download zip file
					saveData(content, certCommonName+ '.zip', 'application/zip');

				});

				/* https://stuk.github.io/jszip/ */

			}  else {

				generalInfo('show', 'error', translateError(data.message), 'li.step.open .alerts');
				return false;

			}

		}

	});





	return;

	var isRealButton = false;

	if ($(this).closest('ul').attr('data-dropdown')) {
	generalInfo('show', 'success', 'Preparing your certificate for download ...');
	} else {
	button.addClass('loading');
	isRealButton = true;
	}

	setTimeout( function(){

		if ($(this).closest('ul').attr('data-dropdown')) {
		generalInfo('hide');
		} else {
		button.removeClass('loading');
		}

	}, 5000);

});



/* INSTALL - HTTPS CHECK */
body.on('click', '[data-action="wizard[install][https_check]"]', function(event) {

	var button = $(this);
	button.addClass('loading');

	var urlToCheck = body.find('[name="wizard[install][url_to_check]"]').val();

	var	postData = {
		domain: urlToCheck
	};

	var postDataJSON = JSON.stringify(postData);
	//console.log(postDataJSON);

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_check_domain_ssl',
		data: ({ postArray: postDataJSON }),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			//alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			button.removeClass('loading');

			if (data.message.has_valid_certificate === 1) {

				body.find('li.step').removeClass('open');
				body.find('li.step:not(.finalize)').addClass('complete').addClass('locked_permanently');

				body.find('li.step.finalize').removeClass('locked_permanently').addClass('open').addClass('complete');

			} else {

                if(data.message.has_valid_certificate === null) {
                    generalInfo('show', 'info', 'This check is currently not working for certificates primarily issued for an IPv4 or IPv6 address.', 'li.step.open .alerts');
                    body.find('li.step.finalize').removeClass('locked_permanently').addClass('open').addClass('complete');
                } else {
                    generalInfo('show', 'error', 'It looks like your certificate has not been installed yet. Please check for errors and try again.', 'li.step.open .alerts');
                    return false;
                }
			}

		}

	});

});



/* INSTALL - SWITCH BETWEEN SERVER TYPES */
body.on('change', '[name="wizard[install][server_type]"]', function(event) {

	var chosenValue = $(this).val();

	body.find('[data-server-type]').hide();
	body.find('[data-server-type="'+chosenValue+'"]').show();

});



/* FORGE - GENERATE KEY PAIR */
function generateKeyPair(csrArray) {

	// generate a key pair
	var keys = forge.pki.rsa.generateKeyPair(2048);

	// store csr values, if not available -> use defaults
	var csrCommonName = csrArray[0];
	var csrOrganizationName = /*csrArray[1] ? csrArray[1] :*/ 'Organization';
	var csrOrganizationUnitName = /*csrArray[2] ? csrArray[2] :*/ 'Department';
	var csrLocalityName = /*csrArray[3] ? csrArray[3] :*/ 'Locality';
	var csrState = /*csrArray[4] ? csrArray[4] :*/ 'State';
	var csrCountryName = /*csrArray[5] ? csrArray[5] :*/ 'US';
	var csrEmailAddress = 'cert_inbox@zerossl.com'; // unused

	// common name must be present
	if (!csrArray[0]) {
	console.log('Error: Commmon Name empty, CSR cannot be generated');
	return false;
	}

	// create a certification request (CSR)
	var csr = forge.pki.createCertificationRequest();
	csr.publicKey = keys.publicKey;
	csr.setSubject([{
	  name: 'commonName',
	  value: csrCommonName
	}, /*{
	  name: 'emailAddress',
	  value: csrEmailAddress
	},*/ {
	  name: 'countryName',
	  value: csrCountryName
	}, {
	  shortName: 'ST',
	  value: csrState
	}, {
	  name: 'localityName',
	  value: csrLocalityName
	}, {
	  name: 'organizationName',
	  value: csrOrganizationName
	}, {
	  shortName: 'OU',
	  value: csrOrganizationUnitName
	}]);

	// sign certification request
	csr.sign(keys.privateKey);

	// verify certification request
	var verified = csr.verify();

	// convert certification request to PEM-format
	var csrPem = forge.pki.certificationRequestToPem(csr);

	// store private key in Forge format
	var privateKey = keys.privateKey;

	// store private key in PEM format - unused!
	var privateKeyPem = forge.pki.privateKeyToPem(keys.privateKey);

	// convert a Forge private key to an ASN.1 RSAPrivateKey
	var rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey);

	// wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
	var privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

	// encrypt private key with our encryption key
	var encryptionKey = getEncryptionKey();

	var privateKeyEncrypted = forge.pki.encryptPrivateKeyInfo(
	  privateKeyInfo, encryptionKey, {
		algorithm: 'aes256',
	  });

	// convert encrypted private key to PEM
	var privateKeyEncryptedPem = forge.pki.encryptedPrivateKeyToPem(privateKeyEncrypted);

	return {
		csr: csrPem,
		privateKeyEncrypted: privateKeyEncryptedPem
	}

	/* https://github.com/digitalbazaar/forge#pkcs8 */
	/* https://github.com/digitalbazaar/forge#pkcs10 */

}



function decryptPrivateKey(encryptedPrivateKey) {

	// we need our encryption key for decryption
	var encryptionKey = getEncryptionKey();

	// decrypts a PEM-formatted, encrypted private key
	var decryptedPrivateKey = forge.pki.decryptRsaPrivateKey(encryptedPrivateKey, encryptionKey);

	// store decrypted private key in PEM format
	var decryptedPrivateKeyPem = forge.pki.privateKeyToPem(decryptedPrivateKey);

	return decryptedPrivateKeyPem;

}



/* INVALIDATE ALL PRIVATE KEYS */
function invalidateAllPrivateKeys() {

	$.ajax({
		type: 'POST',
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_invalidate_private_keys&_cpt=' + getCookie('_cpt'),
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			alert(textStatus + ', ' + errorThrown);
		},
		success: function(data){

			if (data.success === 1) {

				//console.log('invalidateAllPrivateKeys: Success');

			}  else {

				//console.log('invalidateAllPrivateKeys: Error');

			}

		}

	});

}


/* INSTALL - START AUTO REFRESH FUNCTION */
function startAutoRefresh() {

	// refrsh every 15 seconds if user idle time under a minute
	autoRefreshInterval = setInterval(function() {

		// reload page, maximum 100 times
		if (autoRefreshCount < 100) {

			// increase counter by one
			autoRefreshCount ++;

			// reload page
			reloadPage();

		}

	}, 15000);

}

/* INSTALL - STOP AUTO REFRESH FUNCTION */
function stopAutoRefresh() {

	// stop auto refresh
	clearInterval(autoRefreshInterval);

}


/* HIDE SSL FOR FREE NOTICE */
body.on('click', '[data-action="hide_sslforfree_notice"]', function() {

	body.find('.notice.sslforfree').remove();

});


/* AJAX - RESET ACCESS KEY */
body.on('click', '[data-action="generate_eab_credentials"]', function(e) {
	"use strict";
	e.preventDefault();

	var button = $(this);

	button.addClass('loading');

	$.ajax({
		type: "POST",
		url: '/ajax/advanced_ajax_handler.php?type=zerossl_create_acme_eab_account&_cpt=' + getCookie('_cpt'),
		dataType: "json",
		error: function(XMLHttpRequest, textStatus, errorThrown) {
     		//alert(textStatus + ', ' + errorThrown);
  		},
		success: function(data){

			button.removeClass('loading');

			if (data.success === 1) {

				var	customData = {
					eab_kid: data.message.eab_kid,
					eab_hmac_key: data.message.eab_hmac_key
				};

				openPopup('view_eab_credentials', customData);

			}  else {

				generalInfo('show', 'error', translateError(data.message));
				return false;

			}

		}

	});

});


/* HANDLE ZENDESK WIDGET */
function handleZendeskWidget() {

	var suppressWidgetContactForm = false;

	if (body.find('[name="user[subscription_id]"]').val() == 477 || body.find('[name="user[subscription_id]"]').val() == 634) {
	suppressWidgetContactForm = true;
	}

	window.zESettings = {
	  webWidget: {
		contactForm: {
		  suppress: suppressWidgetContactForm
		},
		helpCenter: {
		  suppress: false
		},
	  }
	};

}

// for removing certain default domain variants added by default (e.g. www)
$(document).on('click','.domain .remove_domain', function () {
    let wwwonly = "false";
    if($(this).attr("data-removeDomain") === "root") {
        wwwonly = "true";
    }

    $(this).hide();
    $(this).prev().hide();
    body.find(`[name="wizard[order][domains][domain]strict_domains"]`).val("true").attr("data-wwwonly",wwwonly)
});

// Plans toggle Monthly/Yearly prices
$('body').on('change', '[name="payment_freq"]', function() {
	$('.plans').toggleClass('yearly');
	var frequency = $(this).is(':checked') ? 'yearly' : 'monthly';
	$('.savings-element').toggleClass('enabled');
	body.find('[name="user[payment_frequency]"]').val(frequency);
});

$('body').on('change', '[name="enable_protection"]', function() {
	$('body').toggleClass('protection-enabled');
	$('.protection-element').toggleClass('enabled');
	if ($('.protection-element').hasClass('enabled')) {
		$('.protection-element').html('Enabled');
	} else {
		$('.protection-element').html('Disabled');
	}
	$('.protection-plan, .no-protection-plan, .features.protection-details').not('.current-plan').toggleClass("hidden");
});

$('body').on('click', '[name="file_upload_type"]', function() {
	const fileUploadType = $(this).val();
	$(".http-file-element, .https-file-element").hide();
	$(`.${fileUploadType}-file-element`).show();

	updateVerificationSummary();
});

Youez - 2016 - github.com/yon3zu
LinuXploit