Архив за месяц: Апрель 2015

При показе из WinForms приложения WPF окна в его TextBox-ах не вводится текст

В проекте написанном на WinForms необходимо было показать форму WPF. Показывается, все замечательно. Но... При попытке что-то набрать в TextBox-е в нем отображаются только пробелы. Все остальные клавиши игнорируются. Ларчик открывался просто. При показе WPF окна надо вызывать не Show, а ShowDialog. Иначе ввод не работает. Вот как так, а?

При показе из WinForms приложения WPF окна в его TextBox-ах не вводится текст

В проекте написанном на WinForms необходимо было показать форму WPF. Показывается, все замечательно. Но... При попытке что-то набрать в TextBox-е в нем отображаются только пробелы. Все остальные клавиши игнорируются. Ларчик открывался просто. При показе WPF окна надо вызывать не Show, а ShowDialog. Иначе ввод не работает. Вот как так, а?

Шаблоны проектов для управляемых расширений AutoCAD

Опубликовал шаблоны для разработки и тестирования управляемых расширений для AutoCAD и вертикальных решений на его базе.

Страничка проекта находится здесь. Документация, примеры кода и демонстрационное видео так же присутствуют (ссылки на видео указаны в разделе Additional resources файла справочной системы).

Конструктивные замечания и предложения по теме приветствуются.

Мнение о книге "Атлант расправил плечи"

Если коротко, то как в той присказке про двух дедушек, один боролся за то, чтобы не было богатых, а другой, за то чтобы не было бедных. Автор книги в трех томах рассказывает о том, почему был прав второй дедушка и почему был не прав первый.
Если чуть подлиннее, то книга затянута, особенно третий том. Но в целом написана приятным языком в стиле утопии, ну или, если хотите, антиутопии. Т.е. такие две противоположности и герои потихоньку перемещаются из одной в другую. Да, это даже не спойлер, т.к. понятно с самого начала: наши победят! Кто в книге наши? Одга из крайностей. Автор немного перегибает и отметая одну крайность стремиться броситься во вторую. Нет, в третьей части немного пытается один из главных героев сказать про то, что совсем уж в крайность не надо, но это так, вскользь. Стоит ли читать? Ну почему бы и нет, хотя если рационально смотреть на окружающую действительность и как говорил один из упомянутых дедушек: "Люди всегда были и всегда будут, глупенькими жертвами обмана и самообмана в политике, пока они не научатся за любыми нравственными, религиозными, политическими, социальными фразами, заявлениями, обещаниями разыскивать интересы тех или иных классов.", то... Да все равно читать стоит. Уж очень многие считают эту книгу чуть ли не библией предпринимателей и чтобы можно было понимать откуда у изложенных в книге идей растут ноги. Да, стоит.

Немного о качестве accoreconsole.exe

Как говорится, страна должна знать своих героев... В данном контексте речь пойдёт о багах, с которыми предстоит столкнуться пользователям утилиты accoreconsole.exe. Ранее я уже писал об этом инструменте здесь. За четыре года уж точно можно было бы выявить очевидные ляпы и исправить их. Однако "можно было бы", не означает, что это "было сделано" в реальности.


Все мы прекрасно помним, что издавна, при запуске acad.exe с ключом /p и указанием нужного профиля, этот профиль, ежели он хранится в ARG-файле, импортируется в реестр и устанавливается текущим. Видимо это было скучно и Autodesk решил разнообразить наши серые будни...

Когда я запускаю accoreconsole.exe для AutoCAD 2015 и 2016 с ключом /p, указывающим нужный профиль, хранящийся в ARG-файле, то в последствии, по завершении сеанса accoreconsole и запуская acad.exe этих версий вижу этот профиль в диалоговом окне на вкладке Options (он же установлен и текущим). Это поведение аналогично тому, которое присутствовало в старых версиях AutoCAD, когда accoreconsole.exe ещё и в помине не было. Идём дальше...

Для AutoCAD 2013 и 2014 в диалоговом окне Options в аналогичной ситуации новый профиль не появляется. 

В AutoCAD 2013 после работы accoreconsole.exe я вижу наличие ветки:
HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R19.0\CoreUser\ran\Profiles\
в которой присутствует только запись <<Unnamed Profile>>
Мой профиль не появился.

Подобная картина в AutoCAD 2013 наблюдается и с веткой
HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R19.0\ACAD-B001:409\Profiles
там так же присутствует только запись <<Unnamed Profile>>, а профиль, подключаемый мною через ключ /p не появился.

Т.е. при использовании accoreconsole.exe в AutoCAD 2013 указанный мною при помощи ключа /p профиль, подгружаемый из ARG-файла, не сохранился в реестре нигде, насколько я вижу.

АutoCAD 2014 так же не содержит информации о подключавшемся профиле в своей ветке
HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R19.1\ACAD-D001:409\Profiles
присутствует только <<Unnamed Profile>>, как и в AutoCAD 2013.

Во всех др. версиях AutoCAD, отличных от 2013-го, аналогичная подветка CoreUser\ran\Profiles\ вовсе отсутствует и не появляется в т.ч. и после работы accoreconsole.exe.

Т.о. налицо поведение "кто в лес, кто по дрова".

Не будем останавливаться на "достигнутом", пойдём дальше...

AutoCAD 2013-2015 SP1 x64 Enu.


Если консольное окно accoreconsole.exe закрывать путём нажатия соответствующей кнопки в верхнем правом углу консольного приложения, то значение системной переменной FILEDIA, изменённое обозначенной утилитой в ходе своей работы, остаётся равным 0. Т.е. если в дальнейшем запустить acad.exe, то это соответствующим образом отражается на его работе. Но ежели закрывать консольное окно командами _.quit или _.exit, то такая проблема не наблюдается.

Компания Autodesk порекомендовала (не утруждая себя проверкой работоспособности обозначенной рекомендации):  для того, чтобы не портилась системная переменная FILEDIA в AutoCAD (как и другие системные переменные), нужно использовать ключ запуска /isolate <userid>, где userid - произвольное имя.

Однако, как показала практика, не работает и обозначенное выше решение с /isolate:

Autodesk: В DevHelp подтвердили некорректность работы /isolate с AutoCAD 2015 SP2 и 2016 и передали команде инженеров для анализа.

Про более ранние версии видимо постеснялись написать...

Идём далее...

AutoCAD 2013-2015 x64 Enu

Запускаем accoreconsole.exe и загружаем в него некоторую сборку. Смотрим первый скрин.



Меняем ширину консольного окошка (смотрим второй скрин) и перезапускаем accoreconsole.



Снова загружаем ту же самую сборку. Смотрим третий скрин - для 2015-го и 4-й скрин - для 2013-го. 



Как видим, после изменении ширины консольного окна, мусора стало меньше. При этом в 2013-м он вообще исчез - корректно выводит информацию, в то время как 2015-й дублирует каждую строку:



Autodesk: Замечание приняли и передали в работу Eng Team.

Печальная практика показывает, что зачастую это - стандартная отписка. Многие пользователи хорошо помнят о баге с переключением раскладки клавиатуры при помощи Shift + Alt. Для тех, кто переключает раскладку иным способом - почитать о данном баге можно здесь. Кстати, этот баг, как и многие другие, не устранён до сих пор! Кстати, до сих пор (т.е. и в AutoCAD 2016) присутствует баг, о котором я когда-то писал здесь. Причём второй из них исправляется всего парой строчек кода... Если даже такие простые (но важные) исправления Autodesk не удосуживается делать, то что можно говорить о чём-то более серьёзном?

Все обозначенные выше баги выявляются первым же запуском accoreconsole.exe. Компания Autodesk не тестирует своё программное обеспечение: откомпилировалось, значит можно отправлять на продажу, а юзерам, столкнувшимся с багами, нужно рекомендовать покупку "более новой версии", в которой может быть что-то будет исправлено.

То, что подобным качеством ПО они позорят себя, в компании Autodesk, к сожалению, себя не "грузят", т.к. практика показывает, что главное для них (как и для многих др. современных компаний) - продать (т.е. втюхать), а думать о качестве - это не современно. Покупатели ПО попутно являются и бесплатными тестерами - чем не отличное решение? А то, что они не только тестируют, но и платят деньги за это ПО - так это и вдвойне хорошо: иметь бесплатных тестеров, которые к тому же ещё и немалые деньги платят компании, чей софт тестируют - мечта любой "современной" компании. Потом можно выборочно устранять пару багов (пофиг, что попутно добавится ещё пара-тройка) и попутно прикрутить пару бантиков, вроде глянцевых кнопочек, после чего можно презентовать новую версию... Неплохо устроились ребята... Чувство совести, похоже, им не ведомо к сожалению (имхо).

Работа с файлами Excel пользователем через интерфейс, на основе SpreadsheetGear

Возникла задача дать пользователю возможность ввести данные в приложении, но на основе шаблона загруженного из Excel файла. Или, иными словами, грузиться и показывается пользователю Excel файл. Файл заранее подготовлен и данные можно вводить только в определенные места (отличающиеся от файла к файлу). Стоит задача показать такой файл, выполнить с ним некоторые операции, ну и считать из него данные по завершению ввода.
данная статья сборник небольших примеров решения такой задачи с использование компонента SpreadsheetGear.

1. Установка и подключение в проект
Здесь все просто. Качаем бесплатную версию здесь. Запускаем инсталятор, далее, далее, далее, конечно же, не забыв поставить галку, что вы согласны с лицензией. Запускаем VS, создаем проект WPF и в Панели инструментов видим:
Все, можно перетаскивать в разметку. Для любителей все делать самому, можно добавить в проект ссылки на две библиотеки (все картинки кликабельны):

Ну и в XAML, подключаем пространство имен и размещаем компонент WorkbookView в нужном нам месте:
<Window x:Class="SpreadsheetGearTestProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sg="clr-namespace:SpreadsheetGear.Windows.Controls;assembly=SpreadsheetGear2012.Windows.WPF"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <sg:WorkbookView />
    </Grid>

</Window>
Можно запускать.
Во всех остальных примерах, я буду использовать приложение с вот такой разметнкой главной формы:

Ну и все примеры, это обработчики соответствующих кнопок.
2. Загрузка файла XLS в компонент
private void Load_Click(object sender, RoutedEventArgs e)
{
    // Настраиваем культуру, в рамках которой будет читаться файл,
    // можем, например, использовать не установленную в системе, а задать требуемую нам
    SpreadsheetGear.IWorkbookSet workbookSet =
            SpreadsheetGear.Factory.GetWorkbookSet(System.Globalization.CultureInfo.CurrentCulture);
    // Загружаем книгу
    SpreadsheetGear.IWorkbook workbook = workbookSet.Workbooks.Open("DOC1152016_505.xls");
    // Передаем книгу в компонент
    wvExcel.ActiveWorkbook = workbook;

}
Вот так это выглядит для обычной книги:

А вот так, для книги в которой листы защищены (нет сетки и заголовков строк и столбцов):
Т.к. мне представляет интерес работа именно с защищенными листами, то все остальные картинки будут именно с ними.
3. Скрываем листы книги, которые нам не нужны
Перед началом работы с элементами книги, необходимо заблокировать ее, а по окончании работы освободить.  В остальных примерах я на этом уже не буду останавливаться, но везде будут соответствующие блоки.
wvExcel.GetLock();
try
{
    wvExcel.ActiveWorkbook.ActiveSheet.Visible = SpreadsheetGear.SheetVisibility.Hidden;
}
finally
{
    wvExcel.ReleaseLock();

}
После выполнения этого кода, будет скрыт активный лист и активным станет соседний лист:
При попытке скрыть последний лист, возникает исключение.
4. Работа с именованными блоками
Если в книге есть именованные блоки, то мы можем как внести в них данные, так и считать их. Например, я буду вносить по кнопке почтовый индекс. Блок в котором он находится имеет имя "П000020020001".
private void AddPostCode_Click(object sender, RoutedEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "П000020020001");
        if (name != null)
        {
            var range = name.RefersToRange;
            range.Value = "248021";
            // Т.к. ячейка может быть не на текущем активном листе,
            // то для удобства проверки, перейдем на него
            wvExcel.ActiveSheet = range.Worksheet;
        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Вот так работает:

Со значениями в компонентах для эмуляции Excel, отдельная песня. Value у диапазона или ячейки имеет тип object. У SpreadsheetGear, чтобы определить тип хранящегося значения есть специальное свойство ValueType. Вот так, например, можно проверить какого типа значение храниться в ячейке:
private void CheckType_Click(object sender, RoutedEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "П000020020001");
        if (name != null)
        {
            var range = name.RefersToRange;
            if (range.ValueType == SpreadsheetGear.ValueType.Number)
            {
                MessageBox.Show(string.Format("В ячейке числовой тип значение {0}", (double)range.Value));
            }
            else if (range.ValueType == SpreadsheetGear.ValueType.Logical)
            {
                MessageBox.Show(string.Format("В ячейке логический тип значение {0}", (bool)range.Value));
            }
            else if (range.ValueType == SpreadsheetGear.ValueType.Empty)
            {
                MessageBox.Show("Ячейка пустая");
            }
            else
            {
                MessageBox.Show(string.Format("В ячейке строковый тип значение {0}", range.Value));
            }

        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Если загрузить данные, добавить индекс и попробовать получить тип, то мы увидим:
Если поправить пример с добавлением вот так:
range.Value = 248021;
То при той же последовательности действий результат будет вот такой:

Т.е. в зависимости от типа присвоенного значения, определяется тип ячейки.
Ну и самый интересный эксперимент. Присвоим ячейке дату:
range.Value = DateTime.Now.Date;
Результат будет следующий:

Обращают на себя внимание два факта. Во-первых, дата показывается правильно, а вот тип ячейки определяется как числовой. Печально...
5. Определение ячейки и блока редактируемых пользователем
Речь идет о редактировании ячейки, т.е. пока ячейка не перешла в состояние редактирования события не вызываются. Ну и для решения этой задачи есть два варианта.
В рамках первого способа, мы можем обрабатывать клики мышкой, для этого подписываемся в компоненте на соответствующее событие:
<sg:WorkbookViewGrid.Row="1" x:Name="wvExcel"MouseLeftButtonUp="wvExcel_MouseLeftButtonUp" />
Ну и пишем соответствующий обработчик:
private void wvExcel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        // Перевоим координаты клика мышкой
        // в строку и столбец активного листа
        System.Windows.Point point = e.GetPosition(wvExcel);
        double x = point.X;
        double y = point.Y;
        double row, col;
        wvExcel.LocationToRange(x, y, out row, out col,
            SpreadsheetGear.Windows.Controls.RangeLocationFlags.Headers);

        // Проверяем что кликнули именно в пределах листа и есть столбец и строка
        if (row >= 0.0 && col >= 0.0)
        {
            // Получаем ячейку
            var range = wvExcel.ActiveWorksheet.Cells[(int)row, (int)col];
            // Получаем блок в который входит эта ячейка (если входит)
            var block = range.CurrentRegion; // var block = range.MergeArea; - можно и вот так
            MessageBox.Show(string.Format(
                "Редактируем ячейку ({0}) значение в ней '{1}'.{6}Ячейка входит в блок ({2}) объединяющий строк: {3} и столбцов {4}.{6}Значение в блоке '{5}'.",
                range.Address,
                range.Value,
                block.Address,
                block.RowCount,
                block.ColumnCount,
                ((block.Value as object[,]) ?? new object[,] { { null } })[0, 0],
                Environment.NewLine
                ));
        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Загрузив наш лист и кликнув по ячейке с индексом, мы получим:

На что следует обратить внимание:
а) Хотя мы и подписывались на MouseUp событие вызовется только при первом переходе ячейки в редактирование. Выделение ячейки событие не вызывает, также как и повторные клики на редактируемой ячейке.
б) Получить блок в который входит ячейка можно двумя способами. Разницы в них не заметил.
в). Ни один из способов получения ячейки не позволяет понять, что этот Range именованный:
Второй способ, на мой взгляд более правильный, это обрабатывать события связанные с ячейкой. В данном случае, нас интересует CellBeginEdit. В данном случае, обработчик будет значительно проще:
private void wvExcel_CellBeginEdit(object sender, SpreadsheetGear.Windows.Controls.CellBeginEditEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        // Получаем ячейку
        var range = wvExcel.ActiveCell;
        // Получаем блок в который входит эта ячейка (если входит)
        var block = range.CurrentRegion; // var block = range.MergeArea; - можно и вот так
        MessageBox.Show(string.Format(
            "Редактируем ячейку ({0}) значение в ней '{1}'.{6}Ячейка входит в блок ({2}) объединяющий строк: {3} и столбцов {4}.{6}Значение в блоке '{5}'.",
            range.Address,
            range.Value,
            block.Address,
            block.RowCount,
            block.ColumnCount,
            ((block.Value as object[,]) ?? new object[,] { { null } })[0, 0],
            Environment.NewLine
            ));
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Что самое интересное, выбирая вроде-как активную ячейку, мы на самом деле получаем весь блок и нам доступно его имя:
6. Добавление строк и копирование части листа
В оригинальном листе есть блок:
Я хочу его скопировать и вставить под оригинальный М1. Сделать это можно достаточно просто:
private void CloneM1_Click(object sender, RoutedEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "М1");
        if (name != null)
        {
            var range = name.RefersToRange;
            // Снимаем защиту с листа
            range.Worksheet.Unprotect("DOC1152016_505.xls");
            //// Добавляем строки для копирования в них нашего М1 (формат с какой и по какую строки)
            string address = string.Format("{0}:{1}", range.Row + range.RowCount + 1, range.Row + 2 * range.RowCount);
            range.Worksheet.Cells[address].Insert();
            // Устанавливаем высоту строк аналогично высоте строк в M1
            for (int i = 0; i < range.RowCount; i++)
            {
                range.Worksheet.Cells[range.Row + range.RowCount + i, 0].RowHeight =
                    range.Worksheet.Cells[range.Row + i, 0].RowHeight;
            }
            // Копируем в подготовленные блок М1
            range.Copy(range.Worksheet.Cells[range.Row + range.RowCount, range.Column]);
            // Востанавливаем защиту
            range.Worksheet.Protect("DOC1152016_505.xls");
            // Т.к. ячейка может быть не на текущем активном листе,
            // то для удобства проверки, перейдем на него
            wvExcel.ActiveSheet = range.Worksheet;
        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Обратите внимание, что т.к. я работаю с защищенными листами, перед копированием, мне приходится снимать защиту. Ну и результат:
7. Присвоение имен блокам
Последний на сегодня пример, связанный, кстати, с предыдущим. Блоки подсвеченные синим у меня имен не имеют, я хочу подсвеченным ячейкам внутри М1 эти имена дать, чтобы было удобнее присваивать в них значения.
Вот так выглядит код присвоения имен:
private void NameM1Child_Click(object sender, RoutedEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "М1");
        if (name != null)
        {
            var range = name.RefersToRange;
            var worksheet = range.Worksheet;
            // Ищем все дочерние объединения с учетом цвета фона
            var background = SpreadsheetGear.Color.FromArgb(255, 51, 204, 204);
            List<IRange> childRanges = new List<IRange>();
            for (int column = 0; column < range.ColumnCount; column++)
            {
                for (int row = 0; row < range.RowCount; row++)
                {
                    var cell = worksheet.Cells[range.Row + row, range.Column + column];
                    if (cell.Interior.Color == background)
                    {
                        var block = cell.MergeArea;
                        if (!childRanges.Any(r => r.Row == block.Row && r.Column == block.Column))
                        {
                            childRanges.Add(block);
                        }
                    }
                }
            }
            // Даем им имена
            for (int i = 0; i < childRanges.Count; i++)
            {
                var newName = worksheet.Names.Add(string.Format("П0_{0}", i), string.Format("='{0}'!{1}", childRanges[i].Worksheet.Name, childRanges[i].Address), ReferenceStyle.A1);
            }
        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Несмотря на то, что мы присваивали имена вида П0_0 и П0_1:

но, т.к. мы их присваивали через раздел, то присвоение по имени будет выглядеть:
private void SetM1Child_Click(object sender, RoutedEventArgs e)
{
    wvExcel.GetLock();
    try
    {
        var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "'Раздел 1'!П0_0");
        if (name != null)
        {
            var range = name.RefersToRange;
            // Снимаем защиту с листа
            range.Worksheet.Unprotect("DOC1152016_505.xls");
            range.Value = 100000;
            // Востанавливаем защиту
            range.Worksheet.Protect("DOC1152016_505.xls");
        }
    }
    finally
    {
        wvExcel.ReleaseLock();
    }

}
Чтобы обращаться только по имени, без имени раздела, нужно добавление имени сделать следующим образом:
var newName = wvExcel.ActiveWorkbook.Names.Add(string.Format("П0_{0}", i), string.Format("='{0}'!{1}", childRanges[i].Worksheet.Name, childRanges[i].Address), ReferenceStyle.A1);
Тогда поиск ячейки будет иметь вид:
var name = wvExcel.ActiveWorkbook.Names.Cast<IName>().FirstOrDefault(n => n.Name == "П0_0");
И в первом и во втором случае, если начала присвоить имена, а потом по имени присвоить значение, то результат будет одинаковый:

На этом все, мое мнение, все это весьма неоднозначно и связано с неоправданными сложностями. Всякие WPF вкусности типа Binding применить не получится. Для узкой и специфичной задачи возможно применение этого компонента имеет смысл, ну а так... 

Як зробити зміну (ротацію) зображень на Java Script?


У даній статті розберемо приклад роботи ротації зображень, написаної на Java Script. Рішення досить-таки популярне. Найчастіше використовується як слайдер зображень у верхній частині сайту, прокрутка рекламних банерів або показ слайдів фотогалереї.

Сам скрипт ротації на Java Script вставляємо між тегами <head> і </ head>

Код JavaScript

<script type="text/javascript"><br >
  var array = new Array(<br >
    "images/photo001.jpg",<br >
    "images/photo002.jpg",<br >
  ); //массив с путями к картинкам. Можно по аналогии добавить изображения<br >
  var delay = 2000; // время задержки одного изображения в миллисекундах = 2 сек<br >
  function imageRotation(i) {<br >
    var image = document.getElementById("rotator");<br >
    image.src = array[i];<br >
    i++;<br >
    if (i == array.length) i = 0;<br >
    setTimeout("imageRotation(" + i + ")", delay);<br >
  }<br >
</script>

Вибираємо об’єкт в тілі документа, який повинен стояти між тегами <body> і </ body> і присвоюємо йому id rotator. Візьмемо за приклад зображення і тег <img>

Дивіться також:овощерезка nicer dicer plus

Код HTML

<p><br >
  <img id="rotator" src="" alt="Ротация изображений" width="150" height="150" /><br >
</p>

Спасибі за увагу!

Як стиснути або закодувати JavaScript? Онлайн сервіси


Навіщо потрібно стискати і кодувати код? Стискати слід для зниження ваги файлу або скорочення займаного місця. Що стосується кодування, то це потрібно для тих, хто хоче скористатися Вашим готовим кодом без згоди або як мінімум слова спасибі) Шифровка робить його нечитабельним.
Таким чином, до речі, можна закодувати не тільки код Java Script, але ще і CSS. Перейдемо до сервісів.

Список онлайн сервісів для стиснення та кодування JS

1. JS Crunch
http://www.cfoster.net/jscrunch/
Автор: Charles Foster
Оптимальне шифрування і стиснення. Підтримує UTF-8. З мінусів: не виводить ніякої інформації про виконану роботу — коефіцієнт стиснення, вихідні, кінцеві розміри. Не завжди видає робочий зашифрований код, тому перевіряйте.

2. JavaScript Compressor
http://javascriptcompressor.com/
Автор: Dean Edwards
Онлайн компресор. Надає можливість закодувати код декількома способами.

3. CSS & amp; JavaScript Compressor
http://www.creativyst.com/Prod/3/
Онлайн компресор. Досить дубовий, без будь-яких наворотів, вичищає зайві прогалини, табуляцію і порожні переклади рядків.

Увага! Доведено багатьма життєвими прикладами: завжди зберігайте оригінал коду і перевіряйте працездатність нового стисненого закодованого коду.

Смотрите также:битсы наушники

Так, є сучасні форми стиснення і зчитування: прочитайте про gzip. Однак, не слід забувати про приватних невеликих прикладах, де сервіси можуть стати в нагоді. І як можна частіше займайтеся чищенням і оптимізацією коду. Особливо при високих навантаженнях на сервіс!)