Скрипты и стили плагинов в HEAD. Оптимизация

8

Товарищи разработчики!

Пожалуйста помещайте все любые куски кода javascript и css в отдельные файлы. Вместо использования <style> и <script>

И для вывода прописывайте ссылки для скриптов и css:

<link href="/wa-apps/shop/plugins/MYPLUGIN/css/FILENAME.css?{$wa->version()}" rel="stylesheet">

<script src="/wa-apps/shop/plugins/MYPLUGIN/js/FILENAME.js?{$wa->version()}"></script>

Таким образом браузеру не придется перечитывать кучу одинакового кода при каждом запросе, а он закеширует файлы при первом запросе, что значительно ускорит загрузку сайта!

Так же желательно было бы чтобы модераторы компании вебасист давали рекомендации по оптимизации кода, при виде совсем запущенных случаев работающего, но абсолютно не оптимизированного кода.

23 комментария

  • +3
    Евгений Леман Евгений Леман 8 декабря 2016 10:34 #

    Дитя google pagespeed

  • +1
    Алексей Алексей Webasyst 8 декабря 2016 10:29 #
    все любые куски кода javascript и css в отдельные файлы.

    Это сильно категорично. Иногда удобнее и правильнее все же использовать inline вставку, чем делать лишние запросы.
    Тем более это влечёт с собой дополнительные ограничение в виде того, что во внешних файлах не используются smarty.

    • +1
      Genasyst Genasyst 14 декабря 2016 13:52 #

      Да с любыми кусками я погорячился)

    • +1
      Syrnik.com Syrnik.com 15 марта 2017 15:55 #

      И это опять не 100%. При использовании HTTP/2 выгоднее разбить на много мелких файлов %)

    • +1
      Евгений Леман Евгений Леман 13 декабря 2016 17:09 #

      Создаете вы шаблон для массового использования далекими людьми. Хотите дать из возможность менять основные цвета на те, что они хотят. Давайте, сударь, расскажите как сделать это без выноса стилей в сам шаблон. С JS аналогично.

      А вообще странный подход. Винить продажные темы/плагины широкого потребления в том, что они в вашем персональном случае имеют лишний код. Не подходит - пишите своё.

      • +1
        info@ravencode.ru info@ravencode.ru 13 декабря 2016 18:25 #

        он уже написал как - генерировать js\css файлы

      • +1
        Genasyst Genasyst 13 декабря 2016 18:48 #

        Что же касается js/сss генерируемых, то можно компилировать файлы, сохранять и отдавать как файл! Это конечно не подходит для тем, но для плагинов самое оптимальное решение!

        • +1
          Евгений Леман Евгений Леман 14 декабря 2016 10:03 #

          И в этом способе я тоже могу найти ряд проблем. Но начнем с другого. А хочется ли разработчикам плагинов, которые стоят копейки, так заморачиваться?

          Автору стоит понять, что товары широкого потребления предназначены для других целей. А еще вам, Гена, стоит получше изучить тему оптимизации. Расскажите чем плох JS в шаблоне? Только лишь тем, что зрительно картина не соответствует тому, чему учат в школе. Только клиенты туда не смотрят. А вот лишний файлик = лишний http-запрос. Об этом не написано в "оптимизация для чайников". Но во многих случаях вынос js в саму страницу является более профитным, чем подключение десятка файлов.

          • +1
            Genasyst Genasyst 14 декабря 2016 12:54 #

            Так! Вот явный пример: Плагин Обратный звонок

            Вот строки которые подключают файл js :

            <script type="text/javascript">
            		{include file="../js/callb.frontend.js"}
            	</script>

            Вот код самого файла js/callb.frontend.js


            /**
             * callb.frontend.js
             * Module callbFrontend
             */
            
            /*global $, callbFrontend */
            
            var callbFrontend = (function () { "use strict";
            	//---------------- BEGIN MODULE SCOPE VARIABLES ---------------
            	var
            		onIdinhtmlClick, removeCallbForm, onFormSubmit, initModule;
            	//----------------- END MODULE SCOPE VARIABLES ----------------
            
            	//--------------------- BEGIN DOM METHODS ---------------------
            	removeCallbForm = function () {
            		$('.call-b-bg, .call-b-form').remove();
            	};
            	//--------------------- END DOM METHODS -----------------------
            
            	//------------------- BEGIN EVENT HANDLERS --------------------
            	onIdinhtmlClick = function (event) {
            		event.preventDefault();
            
            		removeCallbForm();
            
            		var bg = $('<div/>');
            		var form = $('<form />');
            		var formTop = $(document).scrollTop() + $(window).height()/2 - '{$callb_settings.style_form_height}'/2;
            		var callbCommentStatus = "{if isset($callb_settings.comment_status)}{$callb_settings.comment_status}{/if}";
            
            		bg.addClass('call-b-bg').css('height', ($(document).height())+'px');
            		form.addClass('call-b-form').css({
            			'background': '#{$callb_settings.style_form_background}',
            			'height': '{$callb_settings.style_form_height}px',
            			'width': '{$callb_settings.style_form_width}px',
            			'top' : formTop+'px'
            		}).prepend(
            			'<div class="call-b-header" style="background: #{$callb_settings.style_header_background}; color: #{$callb_settings.style_header_text_color};">{$callb_settings.text_header_title}<span id="call-b-close-x">x</span></div>' +
            			'<div class="call-b-input"><input type="text" name="callb-name" placeholder="{$callb_settings.text_name_placeholder}" value="" /></div>' +
            			'<div class="call-b-input"><input type="text" name="callb-phone" placeholder="{$callb_settings.text_phone_placeholder}" value="" /></div>' +
                        '<div class="call-b-input"><textarea name="comment" placeholder="{$callb_settings.text_comment_placeholder}"></textarea></div>' +
            			'<div class="call-b-input"><input id="call-b-submit" type="submit" value="{$callb_settings.text_submit_button}" style="background: #{$callb_settings.style_submit_background}; color: #{$callb_settings.style_submit_text_color}; height: {$callb_settings.style_submit_height}px; width: {$callb_settings.style_submit_width}px" /></div>'
            		);
            
            		$('body').prepend(form).prepend(bg);
            
            		$('.call-b-form input[name="callb-name"]').focus();
            
            		{if isset($callb_settings.phone_masked_input) && strlen($callb_settings.phone_masked_input) > 0}
            		$('.call-b-form input[name="callb-phone"]').mask('{$callb_settings.phone_masked_input}');
            		{/if}
            
                    if (callbCommentStatus !== 'on') {
                        $('textarea[name="comment"]').parent('.call-b-input').hide();
                    }
            	};
            
            	onFormSubmit = function (event) {
            		event.preventDefault();
            
            		var n = $('.call-b-input').find('input[name="callb-name"]').val();
            		var p = $('.call-b-input').find('input[name="callb-phone"]').val();
            		var c = $('.call-b-input').find('textarea[name="comment"]').val();
            		var err = $('<div/>');
            		var currentUrl = window.location.href;
            
            		$('.call-b-error').remove();
            		$('.call-b-input').find('input[name="callb-name"], input[name="callb-phone"]').removeClass('call-b-inp-err');
            
            		if ( n.length > 0 && p.length > 0 ) {
            			$.post("{$callback_url}", { "name": n, "phone": p, "comment": c, "url": currentUrl }, function (response) {
            				if (response.data.status === true) {
            					$('.call-b-input').remove();
            					$('.call-b-form').append(
            						'<p class="call-b-ok" style="color: #{$callb_settings.style_thanks_text_color};">{$callb_settings.text_thanks_message} ' + response.data.name + ',</p>' +
            						'<p class="call-b-ok" style="color: #{$callb_settings.style_thanks_text_color};">{$callb_settings.text_more_thanks_message}</p>' +
            						'<div class="call-b-input"><input id="call-b-close" type="button" value=\"{_wp("Close")}\" style="background: #{$callb_settings.style_close_ok_background}; height: {$callb_settings.style_submit_height}px; width: {$callb_settings.style_submit_width}px;" /></div>'
            					);
            				} else {
            					$('.call-b-input').remove();
            					$('.call-b-form').append(
            						'<p class="call-b-ok margins">{_wp("Error occurred when sending message")}</p>' +
            						'<div class="call-b-input"><input class="call-b-close-error" id="call-b-close" type="button" value=\"{_wp("Close")}\" style="background: #{$callb_settings.style_close_error_background}; height: {$callb_settings.style_submit_height}px; width: {$callb_settings.style_submit_width}px;" /></div>'
            					);
            				}
            			}, "json");
            		} else {
            			if ( !(n.length > 0) ) {
            				$('.call-b-input').find('input[name="callb-name"]').focus();
            			} else if ( !(p.length > 0) ) {
            				$('.call-b-input').find('input[name="callb-phone"]').focus();
            			}
            			if ( !(n.length > 0) ) {
            				$('.call-b-input').find('input[name="callb-name"]').addClass('call-b-inp-err');
            			}
            			if ( !(p.length > 0) ) {
            				$('.call-b-input').find('input[name="callb-phone"]').addClass('call-b-inp-err');
            			}
            			err.addClass('call-b-error').text("{_wp('Complete «Name» and «Phone»')}");
            			$('.call-b-form').append( err );
            		}
            	};
            	//------------------- END EVENT HANDLERS ----------------------
            
            	//------------------- BEGIN PUBLIC METHODS --------------------
            	initModule = function () {		
            		$(document).on('click', '{$callb_settings.id_in_html}', onIdinhtmlClick);
            
            		$(document).on('click', '.call-b-bg, #call-b-close-x, #call-b-close', removeCallbForm);
            
            		$(document).keyup(function(event) {
            			if (event.keyCode == 27) { // close callb form when esc key is pressed
            				removeCallbForm();
            			}
            		});
            
            		$(document).on('submit', '.call-b-form', onFormSubmit);
            	};
            
            	return {
            		initModule: initModule
            	};
            	//------------------- END PUBLIC METHODS ----------------------
            }());

            Это идет в head страницы и каждый раз компилируется через смарти!!!!!


            Посмотрев переменные которые передаются и используются для компиляции данного js, понятно что туда передаются только массив настроек $callb_settings.

            Так почему бы не сделать объект


            $.callb = {
            
            settings:{},
            
            init:function(settings) {
            
            this.settings = settings;
            
            }
            
            ///тут методы
            
            };

            А в шаблон передавать только массив json

            <script type="text/javascript" src="{$wa_url}wa-apps/shop/plugins/callb/js/callb_frontend.js"></script>
            <script type="text/javascript">
            	$.callb.init({json_encode($callb_settings)})
            </script>

            Что вы скажете про данный случай?

            1. В моей реализации передается только Json массив

            2. код скрипта будет зfпрошен один раз (далее будет из кеша браться)

            3. никакой лишней компиляции через PHP

            4. вполне удобно читаемый код Js


            • +1
              Syrnik.com Syrnik.com 15 марта 2017 15:59 #

              Про этот конкретный случай скажу, что автор погорячился.

              И что ему вправду стоит попробовать почитать документацию по написанию jQ-плагинов

              Потом подумать и переписать это без jQ совсем. %)

            • +1
              Genasyst Genasyst 14 декабря 2016 13:22 #

              Кстати именно из-за этого плагина я и создал тему((((

              Когда один такой плагин вроде бы ничего страшного, а когда таких будет установлено 30?!!!

              Давайте посчитаем


              <script type="text/javascript">
              		{$start = microtime(true)}
              		{for $i = 0 to 30}
              		{include file="../js/callb.frontend.js"}
              		{/for}
              		{$all_time = microtime(true) - $start}
              
              	</script>
              	<!-- {$all_time} -->

              компиляция занимает 0.012 сек

              компилированный код таких 30 скриптов весит 164kb

              + это все надо отдать браузеру вывод



            • 0
              Genasyst Genasyst 8 декабря 2016 10:57 #

              я не дитя гугл спид. Просто столкнулся с проблемой на одном сайте, там во первых сама тема генерит css цвета через смарти , а еще там стоит четверть всех плагинов. Код head превращается в индусский код! Хотя половина кода могла бы находится в файлах. Да действительно бывают случаи когда надо передать переменную смарти в javascript, я для этого использую json обьект. Что же касается сss, то можно компилировать файлы, сохранять и отдавать как файл

              • +1
                info@ravencode.ru info@ravencode.ru 12 декабря 2016 17:28 #

                50% виденных мной плагинов представляют собой лапшу из серии "х..як, х..як и в продакшн")) да и если говорить о частной разработке, то всем подавай подешевле, вот в итоге и получается подобный говнокод (хотя им и сама WA постоянно грешит - т.ч. понятно откуда сторонние разработчики черпают "вдохновение"). Также согласен с замечанием Евгения.

                • +2
                  Genasyst Genasyst 12 декабря 2016 19:09 #

                  Да! поддерживаю!!!!

                  Проблема в общем-то не особо из-за javascript, а из-за дополнительных запросов в бд плагинами по каждому пуку! многие плагины делают свои выводы через методы хелперов да еще и без хранения дополнительной информации в статических переменных(например массив данных самой категории) и при каждом запросе метода хелпера для получения информации о товаре, которых для показа 50, заново запрашивается инфа текущей категории ( это как пример), а особенно это сказывается на производительности при показе товаров категории!

                  Также создание объектов моделей можно также заносить в пул!

                  Вот простой код хранения моделей плагина:

                  <?php
                  
                  class shopMyPluginModels  {
                  
                      protected static $models = array();
                  
                      public static function get($name) {
                          if(isset(self::$models[strtolower($name)])) {
                              return self::$models[strtolower($name)];
                          } else {
                              $class_name = 'shopMyPlugin'.ucfirst($name).'Model';
                              if(class_exists($class_name)) {
                                  self::$models[strtolower($name)] = new $class_name();
                                  return self::$models[strtolower($name)];
                              }
                              return null;
                          }
                      }
                  }
                  • +1
                    info@ravencode.ru info@ravencode.ru 12 декабря 2016 22:05 #

                    Проще тогда уж singleton использовать.

                    • +1
                      Genasyst Genasyst 13 декабря 2016 00:36 #

                      Мне не проще) Проще пул одиночек! Мне не надо знать является ли объект одиночкой или нет, мне без разницы, я получу все равно копию нужного мне объекта не зависимо от его реализации) Можно еще проверять является ли класс одиночкой и его тогда загружать через метод

                    • +1
                      Syrnik.com Syrnik.com 15 марта 2017 16:00 #

                      Это и есть синглтон. Если присмотреться %)

                      Ну, фабричный метод с кэшем и синглтонами :D

                      • +1
                        Genasyst Genasyst 15 марта 2017 16:08 #

                        Отличие синглтона от статики для использования в WA в том что в смарти нельзя инициализировать классы через new, поэтому синглтон это как защита от использования класса в шаблоне.

                      • +1
                        v-e-y v-e-y 11 февраля 2020 21:32 #

                        Хочу апнуть тему.

                        Это код в head только от 3-х! плагинов.

                        <link href="/wa-apps/shop/plugins/quickorder/js/dialog/jquery.dialog.min.css,q2.6.1.pagespeed.ce.ePe3TBgzxt.css" rel="stylesheet">
                        <link href="/wa-apps/shop/plugins/quickorder/css/frontend.min.css,q2.6.1.pagespeed.ce.ybjZO0ZtfS.css" rel="stylesheet">
                        
                        <script src="/wa-apps/shop/plugins/quickorder/js/dialog/jquery.dialog.min.js,q2.6.1.pagespeed.ce.Ah6M1KSnFw.js"></script>
                        <script src="/wa-apps/shop/plugins/quickorder/js/frontend.min.js,q2.6.1.pagespeed.ce.VFhwSbfguW.js"></script>
                        <script src="/wa-apps/shop/plugins/flexdiscount/js/flexdiscountFrontend.min.js,q4.24.4.pagespeed.ce.jFCYwbpNyD.js"></script>
                        
                        <style id="quickorder-inline-styles" data-inline-css="1">[data-quickorder-pb]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;margin-top:10px;margin-bottom:10px;text-align:center}[data-quickorder-pb]:hover{background:rgba(222,222,222,1)}[data-quickorder-pb]{display:table}.quickorder-form[data-quickorder-pf]{background:transparent;color:#5e5e5e;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}[data-quickorder-pf] .quickorder-methods .s-quickorder-method{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}[data-quickorder-pf] .quickorder-popup{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.quickorder-form [data-quickorder-pfh]{background:transparent;color:#000;font-family:Arial,sans-serif;font-size:24px;font-style:normal;font-weight:normal}[data-quickorder-pf] .quickorder-popup-head{background:rgba(243,243,243,1);color:#000}[data-quickorder-pf] .quickorder-popup{border:2px solid rgba(243,243,243,1)}.quickorder-form [data-quickorder-pt]{font-size:14px;font-style:normal;font-weight:bold}.quickorder-form [data-quickorder-pfs]{padding:7px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;border:1px solid #ccc;width:100%}[data-quickorder-pf] .quickorder-methods .s-quickorder-method{border:1px solid #ccc}[data-quickorder-pf] .quickorder-methods-form .wa-value input,[data-quickorder-pf] .quickorder-methods-form .wa-value select,[data-quickorder-pf] .wa-captcha-input,[data-quickorder-pf] .quickorder-methods-form .wa-value textarea{padding:7px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;border:1px solid #ccc}.quickorder-form [data-quickorder-pff]{padding:20px;text-align:center}.quickorder-form [data-quickorder-pfb]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;text-align:center}.quickorder-form [data-quickorder-pfb]:hover{background:rgba(222,222,222,1)}[data-quickorder-pf] .quickorder-methods .s-quickorder-method:hover,[data-quickorder-pf] .quickorder-methods .s-quickorder-method.selected{background:rgba(243,243,243,.1)}[data-quickorder-pf] .quickorder-quantity-volume:hover{background:rgba(243,243,243,.1)}[data-quickorder-pf] .quickorder-popup input[type="button"]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;text-align:center}[data-quickorder-pf] .quickorder-popup input[type="button"]:hover{background:rgba(222,222,222,1)}[data-quickorder-cb]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;margin-top:10px;margin-bottom:10px;text-align:center}[data-quickorder-cb]:hover{background:rgba(222,222,222,1)}[data-quickorder-cb]{display:table}.quickorder-form[data-quickorder-cf]{background:transparent;color:#5e5e5e;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}[data-quickorder-cf] .quickorder-methods .s-quickorder-method{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}[data-quickorder-cf] .quickorder-popup{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.quickorder-form [data-quickorder-cfh]{background:transparent;color:#000;font-family:Arial,sans-serif;font-size:24px;font-style:normal;font-weight:normal}[data-quickorder-cf] .quickorder-popup-head{background:rgba(243,243,243,1);color:#000}[data-quickorder-cf] .quickorder-popup{border:2px solid rgba(243,243,243,1)}.quickorder-form [data-quickorder-ct]{font-size:14px;font-style:normal;font-weight:bold}.quickorder-form [data-quickorder-cfs]{padding:7px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;border:1px solid #ccc;width:100%}[data-quickorder-cf] .quickorder-methods .s-quickorder-method{border:1px solid #ccc}[data-quickorder-cf] .quickorder-methods-form .wa-value input,[data-quickorder-cf] .quickorder-methods-form .wa-value select,[data-quickorder-cf] .wa-captcha-input,[data-quickorder-cf] .quickorder-methods-form .wa-value textarea{padding:7px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;border:1px solid #ccc}.quickorder-form [data-quickorder-cff]{padding:20px;text-align:center}.quickorder-form [data-quickorder-cfb]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;text-align:center}.quickorder-form [data-quickorder-cfb]:hover{background:rgba(222,222,222,1)}[data-quickorder-cf] .quickorder-methods .s-quickorder-method:hover,[data-quickorder-cf] .quickorder-methods .s-quickorder-method.selected{background:rgba(243,243,243,.1)}[data-quickorder-cf] .quickorder-quantity-volume:hover{background:rgba(243,243,243,.1)}[data-quickorder-cf] .quickorder-popup input[type="button"]{background:rgba(243,243,243,1);color:#000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;font-family:Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;padding:10px 25px;text-align:center}[data-quickorder-cf] .quickorder-popup input[type="button"]:hover{background:rgba(222,222,222,1)}/* Добавляйте свой CSS ниже */
                        .quickorder-button{width:100%;padding:5px 10px;border:1px solid rgba(0,0,0,.1);color:#868e96;background:transparent;margin-top:5px;margin-bottom:0;}
                        .quickorder-form-content{padding-bottom:5px;padding-top:10px;}
                        .quickorder-form-footer{padding-top:5px;}
                        .quickorder-form-head{padding:.5rem;border-bottom:1px solid rgba(0,0,0,.1);}
                        .quickorder-form [data-quickorder-pfb]{width: 100%;}
                        .quickorder-form[data-quickorder-pf]{background:#fff;}
                        .quickorder-row .quickorder-terms{margin:5px 0;}
                        .quickorder-field-name, .quickorder-name{margin-bottom:0;}
                        .quickorder-row, .quickorder-fields{margin:0;}
                        .quickorder-form-content p{margin-bottom:.2rem;}
                        .quickorder-form [data-quickorder-pff]{padding-top:5px;}
                        .quickorder-product{display:none;}
                        .quickorder-form input[type='checkbox']{margin-right:.5rem;}</style><script type='text/javascript'>jQuery(document).ready(function($) {$.quickorder.init({version:'2.6.1',isDebug:'0',messages:{"Select product sku":"\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0442\u043e\u0432\u0430\u0440\u0430","Product with the selected option combination is not available for purchase":"\u0422\u043e\u0432\u0430\u0440 \u0441 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430\u043c\u0438 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0437\u0430\u043a\u0430\u0437\u0430","This product is already selected":"\u0422\u043e\u0432\u0430\u0440 \u0443\u0436\u0435 \u0432\u044b\u0431\u0440\u0430\u043d","Fix the errors above":"\u0418\u0441\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0434\u043e\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438","The shopping cart is empty":"\u041a\u043e\u0440\u0437\u0438\u043d\u0430 \u043f\u0443\u0441\u0442\u0430","Wait, please... Redirecting":"\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435... \u0418\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435","Field is required":"\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435","Fill in required fields":"\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f","Your order is empty":"\u0412\u0430\u0448 \u0437\u0430\u043a\u0430\u0437 \u043f\u0443\u0441\u0442","Fill in captcha field":"\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u044b\u0439 \u043a\u043e\u0434","Terms and agreement":"\u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0438 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f","Phone format is not correct.<br>Use this one:":"\u041d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430.<br>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0442\u0430\u043a\u043e\u0439:","Shipping method has errors. Please, fix them.":"\u041c\u0435\u0442\u043e\u0434\u044b \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u0448\u0438\u0431\u043a\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0438\u0445.","Payment method has errors. Please, fix them.":"\u041c\u0435\u0442\u043e\u0434\u044b \u043e\u043f\u043b\u0430\u0442\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u0448\u0438\u0431\u043a\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0438\u0445.","Minimal sum of order is %s":"\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u0430 %s","Minimal sum of each product is":"\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430 %s","Minimal quantity of products is":"\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u043e\u0432\u0430\u0440\u043e\u0432","Minimal quantity of each product is":"\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u0432\u0430\u0440\u0430","Wait, please..":"\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435.."},currency:{"code":"RUB","sign":"\u0440\u0443\u0431.","sign_html":"<span class=\"ruble\">\u0420<\/span>","sign_position":1,"sign_delim":" ","decimal_point":",","frac_digits":"2","thousands_sep":" "},usingPlugins:1,contactUpdate:0,popupClose:1,minimal:{"total_quantity":"","product_quantity":"","product_sum":"","price":""},productButton:'[data-quickorder-product-button]',cartButton:'[data-quickorder-cart-button]',analytics:{"cart":{"ga_counter":"","ya_counter":"20868589","yaecom":"","yaecom_goal_id":"","yaecom_container":"","ya_fopen":"openFormQO","ya_submit":"sendFormQO","ya_submit_error":"","ga_category_fopen":"","ga_action_fopen":"","ga_category_submit":"","ga_action_submit":"","ga_category_submit_error":"","ga_action_submit_error":""},"product":{"ga_counter":"","ya_counter":"20868589","yaecom":"","yaecom_goal_id":"","yaecom_container":"","ya_fopen":"openFormQO","ya_submit":"sendFormQO","ya_submit_error":"","ga_category_fopen":"","ga_action_fopen":"","ga_category_submit":"","ga_action_submit":"","ga_category_submit_error":"","ga_action_submit_error":""}},urls:{getProductSkus:'/quickorder/getProductSkus/',shipping:'/quickorder/shipping/update/',update:'/quickorder/update/',load:'/quickorder/load/',payment:'/quickorder/payment/',send:'/quickorder/send/',service:'/quickorder/service/update/',cartSaveUrl:{shop:'https://www.noname.com/cart/save/',plugin:'https://www.noname.com/onestep/save/'},cartDeleteUrl:{shop:'https://www.noname.com/cart/delete/',plugin:'https://www.noname.com/onestep/delete/'},cartAddUrl:{shop:'https://www.noname.com/cart/add/',plugin:'https://www.noname.com/onestep/add/'}}});});</script><style>i.icon16-flexdiscount.loading{background-image:url(https://www.noname.com/wa-apps/shop/plugins/flexdiscount/img/loading16.gif)}i.flexdiscount-big-loading{background:url(https://www.noname.com/wa-apps/shop/plugins/flexdiscount/img/loading.gif) no-repeat}.fl-is-loading > * { opacity: 0.3; }.fl-is-loading { position:relative }.fl-is-loading:after{ position:absolute; top:0;left:0;content:"";width:100%;height:100%; background:url(https://www.noname.com/wa-apps/shop/plugins/flexdiscount/img/loader2.gif) center center no-repeat}.fl-loader-2:after{ position:absolute; top:0;left:0;content:"";width:100%;height:100%; background:url(/wa-content/img/loading16.gif) center center no-repeat}i.icon16-flexdiscount{background-repeat:no-repeat;height:16px;width:16px;display:inline-block;text-indent:-9999px;text-decoration:none!important;vertical-align:top;margin:-.1em .25em 0 0}i.flexdiscount-big-loading{display:inline-block;width:32px;height:32px;margin:15px 0}.flexdiscount-coup-del-block,.flexdiscount-loader{display:none}.align-center{text-align:center}.flexdiscount-coup-result,.flexdiscount-form,.flexdiscount-price-block,.flexdiscount-user-affiliate,.flexdiscount-user-discounts{margin:10px 0}.flexdiscount-coup-result{color:green}.flexdiscount-coup-result.flexdiscount-error{color:red}.flexdiscount-max-affiliate,.flexdiscount-max-discount{font-size:1.5em;color:#c03;font-weight:600}.flexdiscount-coupon-delete:before{content:'x';padding:5px;-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%;border:2px solid red;width:.5em;height:.5em;display:inline-block;text-align:center;line-height:.5em;margin-right:5px;font-size:1.3em;color:red;font-weight:700;vertical-align:middle}.flexdiscount-price-block{display:inline-block}.flexdiscount-product-discount{display:table}.flexdiscount-my-content>div{padding:10px}.flexdiscount-discounts-affiliate{color:#c03;background:#fff4b4;padding:5px 10px;border-radius:20px}.flexdiscount-alldiscounts{clear:none;background-color:#FFFFFF;border:1px solid #DDDDDD;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;margin:10px 0}
                        .flexdiscount-alldiscounts-heading{background:#fff4b4;text-transform:uppercase;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;border-top-right-radius:3px;padding:10px 15px}
                        .flexdiscount-alldiscounts-heading .h3{font-size:14px;margin:0;padding:0;color:#444}
                        .flexdiscount-alldiscounts-body,.flexdiscount-alldiscounts .flexdiscount-body{padding:15px}
                        .flexdiscount-alldiscounts table{width:100%}
                        .flexdiscount-alldiscounts ul{margin:0}
                        .flexdiscount-alldiscounts .flexdiscount-table{border-left:1px solid #000;border-top:1px solid #000;width:100%;margin:0}
                        .flexdiscount-alldiscounts .flexdiscount-table td,.flexdiscount-alldiscounts .flexdiscount-table th{color:#000;border:1px solid #000;padding:5px}
                        .fl-discount-skus{margin-bottom:10px}
                        tr.fl-discount-skus td{padding:10px 5px}
                        .flexdiscount-product-discount{display:table}
                        .flexdiscount-pd-block{background-color:#FFFFFF;border:1px solid #DDDDDD;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;margin:10px 0}
                        .flexdiscount-pd-block .flexdiscount-heading,#yourshop .flexdiscount-pd-block .flexdiscount-heading{background:#163bdb;text-transform:uppercase;border-color:#DDDDDD;color:#333333;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;border-top-right-radius:3px;padding:10px 15px}
                        .flexdiscount-pd-block .flexdiscount-heading .h3{font-size:14px;margin:0;padding:0;color:#fff}
                        .flexdiscount-pd-block .flexdiscount-body{padding:15px}
                        .flexdiscount-pd-block ul{margin:0}
                        .flexdiscount-pd-block .flexdiscount-table{border-left:1px solid #000;border-top:1px solid #000;width:100%;margin:0}
                        .flexdiscount-pd-block .flexdiscount-table td,.flexdiscount-pd-block .flexdiscount-table th{color:#000;border:1px solid #000;padding:5px}
                        .flexdiscount-discounts{clear:both;overflow:hidden;background-color:#FFFFFF;border:1px solid #ddd;margin:10px 0}
                        .flexdiscount-discounts-heading{background:#eee;text-transform:uppercase;color:#333333;padding:10px 15px}
                        .flexdiscount-discounts-heading .h3{font-size:14px;margin:0;color:#444}
                        .flexdiscount-discounts-body{padding:0}
                        .flexdiscount-discounts table{width:100%}
                        .flexdiscount-discounts-body ul{list-style:none;padding:0;margin:0}
                        .flexdiscount-discounts-body li{padding:10px 15px;background-color:#fefce3;margin:5px 0}
                        .flexdiscount-discounts-price{color:#e8385c;display:inline-block}
                        .flexdiscount-coup-result{color:green}
                        .flexdiscount-coup-result.flexdiscount-error{color:#ff0000}
                        .flexdiscount-coupon-delete:before{}
                        .flexdiscount-denydiscounts{clear:none;background-color:#FFFFFF;border:1px solid #DDDDDD;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;margin:10px 0}
                        .flexdiscount-denydiscounts-heading{background:#ff0000;text-transform:uppercase;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;border-top-right-radius:3px;padding:10px 15px}
                        .flexdiscount-denydiscounts-heading .h3{font-size:14px;margin:0;padding:0;color:#fff}
                        .flexdiscount-denydiscounts-body,.flexdiscount-denydiscounts .flexdiscount-body{padding:15px}
                        .flexdiscount-denydiscounts table{width:100%}
                        .flexdiscount-denydiscounts ul{margin:0}
                        .flexdiscount-denydiscounts .flexdiscount-table{border-left:1px solid #000;border-top:1px solid #000;width:100%;margin:0}
                        .flexdiscount-denydiscounts .flexdiscount-table td,.flexdiscount-denydiscounts .flexdiscount-table th{color:#000;border:1px solid #000;padding:5px}
                        .flexdiscount-price-block{display:inline-block}
                        .flexdiscount-my-content > div{padding:10px}
                        .flexdiscount-discounts-affiliate{color:#c03;background:#fff4b4;padding:5px 10px;border-radius:20px}
                        .flexdiscount-max-discount,.flexdiscount-max-affiliate{font-size:1.3em;color:#c03;font-weight:600}</style>
                                        <script>
                                        $(function() {
                                            $.flexdiscountFrontend = new FlexdiscountPluginFrontend({ 
                                                urls: {
                                                    couponAddUrl: '/flexdiscount/couponAdd/',
                                                    updateDiscountUrl: '/flexdiscount/update/',
                                                    refreshCartUrl: '/flexdiscount/cartUpdate/',
                                                    deleteUrl: '/flexdiscount/couponDelete/',
                                                    cartSaveUrl: {
                                                        shop: 'https://www.noname.com/cart/save/',
                                                        plugin: 'https://www.noname.com/onestep/save/'
                                                    },
                                                    cartDeleteUrl: {
                                                        shop: 'https://www.noname.com/cart/delete/',
                                                        plugin: 'https://www.noname.com/onestep/delete/'
                                                    },
                                                    cartAddUrl: {
                                                        shop: 'https://www.noname.com/cart/add/',
                                                        plugin: 'https://www.noname.com/onestep/add/'
                                                    }
                                                },
                                                updateInfoblocks: 1,
                                                hideDefaultAffiliateBlock: '0',
                                                ss8forceUpdate: '0',
                                                addAffiliateBlock: '',
                                                loaderType: 'loader1',
                                                locale: 'ru_RU',
                                                settings: [],
                                                shopVersion: '8.8.1.29'
                                                    
                                            });
                                        });
                                    </script>
                                    <script>
                        (function(b,e,d,a){b[e]=b[e]||{_initialized:false,save_url:false,heartbeat_url:false,save_timer:false,bind_timer:false,heartbeat_timer:false,customer_data:{},selectors:{},init:function(c,g,f){if(this._initialized){return}this.initialized=true;this.save_url=c;this.heartbeat_url=g;this.customer_data=f;this._init_selectors();b[e]._bind();b[e].heartbeat()},save:function(){var c=b(this).closest("form, .quickorder-form");if(c.length){clearTimeout(b[e].save_timer);b[e].save_timer=setTimeout(function(){var f={};c.find("[data-carts-field]").each(function(h,g){f[b(g).data("carts-field")]=b(g).val()});console.log(b[e].save_url,f);if(b[e].save_url&&f){b.post(b[e].save_url,f)}},a)}},heartbeat:function(){if(this.heartbeat_url){b.get(this.heartbeat_url)}},_bind:function(){b("input:not([data-carts-checked]),select:not([data-carts-checked])").each(function(c,g){var f=b(g);f.attr("data-carts-checked",true);b.each(b[e].selectors,function(h,i){if(f.is(i.selector)){f.attr("data-carts-field",i.field).on("change blur",b[e].save);if(b[e].customer_data[h]&&!f.val()){f.val(b[e].customer_data[h])}return false}})});clearTimeout(b[e].bind_timer);b[e].bind_timer=setTimeout(b[e]._bind,d)},_init_selectors:function(){var g,f,c=["email","phone","firstname","lastname","middlename","name"];for(g in c){f=c[g];b[e].selectors[f]={field:"customer["+f+"]",selector:'[name="customer['+f+']"], [name="fields['+f+']"], [name="quickorder_fields['+f+']"], [name="auth[data]['+f+']"]'}}}}})(jQuery,"shop_carts_plugin",3000,500);
                        (function ($) {
                        
                        })(jQuery)
                        </script>
                        <style type="text/css">
                            .fprview-wrapper { background: #FFF; float: left; }
                        
                        .inline-block { display: inline-block; }
                        
                        .fprview-top { background: #21a6de none repeat scroll 0 0; box-sizing: border-box; float: left; height: 60px; margin: 0; padding: 0 25px; width: 100%; }
                        .fprview-top .product-name { color: #ffffff; float: left; line-height: 60px; margin: 0; padding: 0; }
                        .fprview-top .hint { color: #ffffff; font-size: 1.4em; line-height: 55px; margin: 0 0 0 20px; }
                        
                        .fprview-left { float: left; margin: 30px 0 0 30px; width: 260px; }
                        .fprview-left .product-images { height: auto; width: 240px; }
                        .fprview-left .product-images img { width: 100%; }
                        .fprview-left .product-link { color: #777; float: left; line-height: 35px; text-align: center; width: 100%; }
                        .fprview-left .product-link { margin: 15px 0 0; }
                        .fprview-left .product-link a { color: #21a6de; text-decoration: underline; }
                        
                        .fprview-right { float: right; margin: 30px 30px 0 0; width: 460px; }
                        .fprview-right * { color: #444; }
                        .fprview-right .product-info-tab { background: #fafafa none repeat scroll 0 0; border-left: 1px solid #21a6de; border-top: 1px solid #21a6de; border-right: 1px solid #21a6de; border-bottom: 0 none; border-top-left-radius: 4px; border-top-right-radius: 4px; cursor: pointer; float: left; height: 30px; line-height: 30px; margin: 3px 2px -1px 0; padding: 0 20px; position: relative; transition: all 0.2s ease-in 0s; }
                        .fprview-right .product-info-tab.active { height: 33px; font-weight: bold; margin: 0 2px -1px 0; }
                        .fprview-right .product-info-block { background: #fafafa none repeat scroll 0 0; border: 1px solid #21a6de; box-sizing: border-box; display: none; float: left; padding: 10px 20px; width: 100%; }
                        .fprview-right .product-info-block.active { display: block; }
                        .fprview-right #product-features { width: 100%; }
                        .fprview-right #product-features td.name { min-width: 50%; padding-right: 5%; }
                        
                        .fprview-wrapper .fprview-right .product-info-blocks #product-features img,
                        .fprview-wrapper .fprview-right .product-info-blocks #product-description img { width: 100%; }
                        
                        .fprview-bottom { background: #21a6de none repeat scroll 0 0; float: left; height: 110px; margin: 30px 0 0; width: 100%; }
                        .fprview-bottom .fprview-price-wrapper { text-align: center; }
                        .fprview-bottom .compare-price { color: #ffffff; float: left; font-size: 18px; margin: -8px 0 0 0; text-decoration: line-through; text-align: left; width: 100%; }
                        .fprview-bottom .price { color: #ffffff; float: left; font-size: 45px; font-weight: bold; margin: 0 0 0 10px; text-align: left; width: 100%; }
                        .fprview-bottom .product-link { border: 2px solid #ffffff; border-radius: 6px; color: #ffffff; display: block; float: right; font-size: 16px; font-weight: bold; height: 45px; line-height: 45px; margin: 30px 30px 0 0; text-align: center; text-decoration: none; width: 230px; transition: all 0.2s ease-in 0s; }
                        .fprview-bottom .product-link:hover { font-size: 18px; height: 55px; line-height: 55px; margin: 25px 25px 0 0; width: 250px; }
                        
                        .fprview-bottom .fprview-left { width: 300px; }
                        
                        .bx-wrapper { position: relative; margin: 0 auto 20px; padding: 0; *zoom: 1; }
                        .bx-wrapper .bx-viewport { box-shadow: none; }
                        .bx-wrapper .bx-controls-direction a { position: absolute; top: 50%; margin-top: -16px; outline: 0; width: 32px; height: 32px; text-indent: -9999px; z-index: 9999; }
                        .bx-wrapper .bx-prev { left: 10px; background: url("/wa-data/public/shop/products/14/webp/apps/shop/plugins/fprview/util/bxslider/img/controls.webp") no-repeat 0 -32px; }
                        .bx-wrapper .bx-next { right: 10px; background: url("/wa-data/public/shop/products/14/webp/apps/shop/plugins/fprview/util/bxslider/img/controls.webp") no-repeat -43px -32px; }
                        
                        .bx-wrapper .bx-controls-direction a { height: 25px; margin-top: -12px; top: 35%; width: 25px; }
                        .bx-wrapper .bx-controls-direction a { height: 31px; width: 32px; }
                        
                        .bx-wrapper img { margin: 0 auto; }
                        
                        @media (min-width:320px) and (max-width: 600px) {
                            .fprview-right { float: left; margin: 30px 10px 0; width: 80%; }
                            .fprview-bottom .product-link { display: none; }
                        }
                        @media (min-width: 601px) and (max-width: 820px) {
                            .fprview-right { float: left; margin: 30px 30px 0; width: 80%; }
                            .fprview-bottom .product-link { display: none; }
                        }
                        @media (min-width: 821px) and (max-width: 1024px) {
                            .fprview-right { float: left; margin: 30px 30px 0; width: 90%; }
                            .fprview-bottom .product-link { font-size: 12px; margin: 30px 10px 0 0; width: 120px; }
                            .fprview-bottom .product-link:hover { font-size: 13px; margin: 25px 10px 0 0; width: 120px; }
                        }
                        @media (min-width: 1025px) and (max-width: 1180px) {    
                            .fprview-right { width: 260px; }
                            .fprview-bottom .product-link { width: 170px; }
                            .fprview-bottom .product-link:hover { width: 170px; }
                        }
                        @media (min-width: 1181px) and (max-width: 1300px) {    
                            .fprview-right { width: 320px; }
                        }
                        @media (min-width: 1301px) and (max-width: 1400px) {    
                            .fprview-right { width: 420px; }
                        }
                            .fprview-more-info {
                                background-color: #21a6de;
                                color: #ffffff;
                            }
                            .fprview-more-info:hover {
                                background-color: #1196ce;
                                color: #dddddd;
                            }
                        </style>
                        
                        <style>
                        .fprview-more-info {
                            border: 0 none;
                            border-radius: 2px;
                            cursor: pointer;
                            display: block;
                            font-size: 1.1em;
                            font-weight: normal;
                            height: auto;
                            // margin: 40% 10% 0;
                            opacity: 0.7;
                            padding: 10px 0;
                            position: absolute;
                            text-align: center;
                            text-decoration: none;
                            width: 80%;
                            z-index: 999;
                        }
                        .fprview-more-info:hover {
                            opacity: 1;
                        }
                        </style>
                        
                        <link media="screen" type="text/css" href="/wa-apps/shop/plugins/fprview/util/fancybox/jquery.fancybox.css.pagespeed.ce.oaXK_MZuXY.css" rel="stylesheet">
                        <script type="text/javascript" src="/wa-apps/shop/plugins/fprview/util/fancybox/jquery.fancybox.js.pagespeed.ce.TZku_Vazcw.js"></script>
                        
                        <script type="text/javascript">
                            /**
                         * fprview.frontend.js
                         * Module fprviewFrontend
                         */
                        
                        /*global $, fprviewFrontend */
                        
                        //------------------- BEGIN JQUERY FUNCTIONS ------------------
                        //-------------------- END JQUERY FUNCTIONS -------------------
                        
                        var fprviewFrontend = (function () { "use strict";
                            //---------------- BEGIN MODULE SCOPE VARIABLES ---------------
                            var
                                initModule;
                            //----------------- END MODULE SCOPE VARIABLES ----------------
                        
                            //------------------- BEGIN PUBLIC METHODS --------------------
                            initModule = function () {
                        
                                $(document).on('click', '.fprview-more-info', function(event){
                                    event.preventDefault();
                        
                                    $.fancybox({
                                        type     : 'ajax',
                                        href     : $(this).attr('href'),
                                        autoSize : false,
                                        width    : "60%",
                                        height   : "auto"
                                    });
                        
                                            });  
                        
                                
                            };
                        
                            return {
                                initModule: initModule
                            };
                            //------------------- END PUBLIC METHODS ----------------------
                        }());
                        </script>
                        
                        <script type="text/javascript">
                            $(document).ready(function () {
                                fprviewFrontend.initModule();
                            });
                        </script>

                        Добавить комментарий

                        Чтобы добавить комментарий, зарегистрируйтесь или войдите