scripts

пятница, 20 сентября 2013 г.

Повторная активация Windows Vista Buisness

Возможна ситуация, когда произвели замену материнской платы допустим. Тогда OEM версия windows отказывается загружаться.
Предлагаю такое решение, возможно не совсем правильное, но рабочее.
1. Сделать резервную копию важной информации. Можно подключить винт к рабочей системе и скопировать данные на другой комп.
2. Снести активацию.
- cmd run as administrator
- "slmgr -rearm"
3. Активировать снова.

понедельник, 9 сентября 2013 г.

Работы Катерины 1 курс.

Дочь решила сжечь свои работы за первый курс, но мне жалко навсегда расстаться с ее работами - в них столько труда и старания.
Решил оцифровать ее работы и создать фотоальбом.

пятница, 23 августа 2013 г.

Немного о JavaScript. Функции. Замыкания.

Понятие замыкания тесно связан с пониманием области видимости. Еще раз отмечу тот факт, что JavaScript не поддерживает области видимости блока, только функции определяют область видимости. Если я внутри функции определю внутреннюю функцию, то это внутренняя функция  будет иметь доступ к параметрам и переменным той функции в которой она определена - это свойство называют замыканием. Замыкания - это сильная сторона JavaScript.
Работая с замыканиями надо быть аккуратным - иначе результат может не оправдать ваших ожиданий. Рассмотрим такой пример: есть отряд курсантов и мы произвели расчет по порядку. То есть первый курсант - "первый", второй - "второй" и т.д. Теперь мы хотим обратиться к курсанту и узнать его порядковый номер.
Создадим функцию stroy().
function stroy() {
  var poryadok = ["первый", "второй", "третий"],
      i,
      kursants = [];
  for (i = 0; i < 3; i++) {
    kursants[i] = function () {
      return poryadok[i];
    };
  }
  return kursants;
}

Теперь мы хотим обратиться к курсанту и он должен сказать свой порядковый номер, что ж попробуем.
var otryad = stroy();
console.log(otryad[2]());

Мы рассчитываем увидеть "третий", но увы получаем
undefined
Хм, не совсем то, что мы ожидали. Давайте разберемся в чем дело и исправим нашу программу. Самый первый вопрос, который приходит в голову, а какое значение имеет переменная i, когда мы возвращаем poryadok[i]. Для отладки закоментируем строку
//return poryadok[]
и напишем
console.log(i)
Теперь видим, что в момент вызова poryadok[i] переменная i равна 3. Получается мы вышли за предел массива и получили вполне заслуженно undefined. Особенность заключается в том, что внутренняя функция при замыкании получает значение переменной внешней функции по ссылке. Получается, что после окончания цикла, переменная i будет иметь значение 3, которое по ссылке и получит внутренняя функция. Есть способ обойти эту особенность и получить нужное поведение. Для этого будем использовать немедленно вызываемую функцию.

function stroy() {
  var poryadok = ["первый", "второй", "третий"],
      i,
      kursants = [];
  for (i = 0; i < 3; i++) {
    kursants[i] = (function (num) {
      return function () {
        return poryadok[num];
      }
    })(i);
  }
  return kursants;
}

var otryad = stroy();

console.log(otryad[2]());

Запустим на исполнение и увидим в результате
"третий"
Вот теперь другое дело. Что ж на этом все. Далее поговорим о прототипах и наследовании.

четверг, 22 августа 2013 г.

Программа для маммографии. Прототип и выбор технологий.

Продолжаем разработку.
На основании пожеланий заказчика я сделал прототип приложения. Прототип разрабатывал в Microsoft Expression Blend 4.
Теперь необходимо определиться - что использовать для реализации и где хранить данные.

среда, 21 августа 2013 г.

Программа для маммографии. Начало.

Появилась задача написать программу для маммографии. Суть в том, чтобы хранить снимки и описания к ним, что позволит врачу поднять историю больного, а также появится материал для статистического анализа. Задачу сформулировал заведующий отделением лучевой диагностики Лев Яковлевич. После нескольких часов обсуждения программы у меня появилось понимание в целом - что собственно надо. Конечно во время обсуждения я пытался делать зарисовки, которые послужат материалом для создания прототипа программы.

Вот такие получились зарисовки:

1. Требуется разделение прав доступа. Будет две роли: Лаборант и Врач. Лаборант делает снимки и работает с карточкой пациента, у него не будет доступа к описанию снимков. Врач делает описание снимков, у него будет доступ и к функциям Лаборанта.
2. Работа с программой будет начинаться с авторизации. После успешной авторизации появляется возможность найти пациента в базе.
3. Окно поиска будет всплывающим (pop-up).

 4. Результаты поиска будут выводиться основное окно.

 5. Справа в отдельной колонке будут отображаться даты приема для выбранного пациента с указанием наличия снимков (или отсутствия). Смысл такой: приходит пациент на прием, лаборант делает запись о приеме, делает снимки и складывает их отдельную папку. Врач проводит описание снимков, делает заключение и прикрепляет сканы снимков к описанию с сохранением их в базе. Таким образом необходимо сразу понять есть ли у пациента по данному приему прикрепленные снимки. По нажатию на дату приема будет появляться pop-up окно с текстом описания и прикрепленными снимками.

6. Если пациента в базе нет, то необходимо его создать. По нажатию на кнопку "Новый" будет появляться pop-up окно для ввода данных о новом пациенте.

7. Врач будет находить пациентов за указанную дату и проводить описание снимков, прикрепляя сканы снимков. Нужна будет индикация - есть ли у пациента описание или нет.

Теперь все готово, чтобы составить прототип приложения.

среда, 7 августа 2013 г.

Немного о JavaScript. Функции.

Функции - это объекты, которые могут вызываться (выполняться). Самая важная особенность функций в том, что они образуют собственные области видимости. Причем в JavaScript только через функцию возможно задать область видимости. Если переменная не входит ни в какую функцию, то она будет глобальной.
JavaScript удивительный язык. Функции в JavaScript - это базис, понимание которого особенно важно. Конечно я в институте изучал по программе C и C++ - там тоже есть понятие функции, но не стоит смешивать мух и котлеты. Вообще хорошо бы опустошить свой "сосуд" и подойти к изучению функций JavaScript с чистого листа, не используя полученные представления из C и C++.
Функции - это данные, их можно хранить в переменных, объектах и массивах, передавать в качестве аргументов и возвращать в качестве результата. Конечно трудно в небольшой статье глубоко раскрыть работу с функциями в JavaScript, но основные моменты я попытаюсь освятить и дать пищу для размышлений.

Функция - выражение

   Именованная функция-выражение
var hello = function hello( name ) {
  console.log('Hello ' + name + '!');
};
   Анонимная функция
var hello = function ( name ) {
  console.log('Hello ' + name + '!');
};
Внимание: заключительная точка с запятой обязательна.

Функция-объявление 

function ( name ) {
  console.log('Hello ' + name + '!');
}
Здесь видно, что если бы анонимная функция не присваивалась переменной (такое как раз встречается при использовании функции обратного вызова), то разницы между двумя определениями нет. В этом случае необходимо посмотреть на контекст, в котором определяется функция.
Для функций-объявлений главное запомнить, что эти функции могут появляться только внутри функций или в глобальной области видимости. Они не могут присваиваться переменным или свойствам, так же не могут передаваться в качестве параметров другим функциям. Есть еще одна особенность функций-объявлений - при "подъеме" вместе с именем функции поднимается ее определение (для именованны функций-выражений "поднимается" только имя).
Эх ностальгия, когда то я начинал работать с JavaScript используя в основном функции-объявления как средство структурирования кода (хотя при разработке модулей nodejs использую их довольно часто).

Функции обратного вызова

Здесь как раз используется та особенность, что функции могут передаваться в качестве параметров. В JavaScript многие вещи делаются асинхронно и функции обратного вызова позволяют удобно работать с асинхронностью. При синхронном выполнении программы, необходимо написать набор инструкций, которые выполняться друг за другом. Например, если мы хотим прочитать файлы какой-то директории:
открыть директорию прочитать файлы
Конечно, при таком подходе все понятно, пока директория не будет открыта, файлы не начнут читаться, но минус в том, что выполнение программы приостанавливается, а запрос к файловой системе "стоит" довольно дорого. Как раз благодаря скорости работы асинхронная модель JavaScript позволяет реализовывать высоконагруженные web сервисы.
В асисинхронном варианте этот пример примет такой вид:
до... открыть директорию ( прочитать файлы ) после...
В коде мы указывает интерпритатору, прочитать файлы после окончания открытия директории, при этом выполнение программы не приостанавливается. Очень часто в качестве функции обратного вызова используют анонимную функцию. Приведу пример для nodeJS.
fs.readdir(subdir, function (err, files) {
  if (!err) {
    работа с files
  } else {
    сообщение об ошибке
  }
});
Вот еще пример использование callback функции.
function say (callback) {
  callback();
}
function hi () {
  console.log('Hi!');
}
say(hi);

 Внимание: при передаче функции в качестве параметра круглые скобки не указываются. Указание круглых скобок приводит к выполнению функции, а нам надо передать лишь ссылку на функцию.

Приватные функции.

Повторюсь, что функции это данные. Значит допустимо объявить функцию внутри функции. Такая внутренняя функция не будет доступна извне, то есть будет приватной.

Рассмотрим такой пример:
function main() {
  function inner() {
    return "inner function.";
  } 
  return "Main function call the " + inner();
}
Вызовем main:

main()
"Main function call the inner function."

Попробуем вызвать inner:
inner()
"inner is not defined"

Чтож, думаю идея понятна, двигаемся дальше.


Self-invoking function. Немедленно вызываемые функции.

Такая функция вызывается немедленно, в точке ее определения.

Вот, кстати, еще вариант применения анонимных функций (помимо callback).

(function () {
  console.log('Function is run.');
}());
Результат:
"Function is run."

В немедленно вызываемые функции можно передавать параметры. Вот довольно распространенный прием.

(function ($) {
  $('#content').append('Hello!');
}(jQuery));

Немедленно вызываемые функции позволяют возвращать значения.

Немедленно вызываемые функции позволяют создавать изолированную область видимости и возвращать публичные методы (шаблон "модуль").

На этом пока все, впереди разговор про замыкания.

Формирование плей-листа на nodejs. Продолжение.

В первой статья я описал задачу формирования плей-листа и ее решение. Теперь возникла необходимость немного усовершенствовать программу. В этой статье я и хочу описать те изменения, которые я внес.

1.Объявления.

Немного расскажу о структуре плей-листа. Суть такая. Есть две папки notice/ и videos/.
В notice/ находятся объявления, которые надо часто показывать, а в videos/ - каталоги с роликами из которых случайным образом и формируется плей-лист. Таким образом структура плей-листа примерно такая:

ролик из videos/subdir1/
ролик из notice/
ролик из videos/subdir2/
ролик из notice/

Теперь появилась необходимость - обеспечить возможность указания нескольких notice в заданном порядке.

ролик из videos/subdir1/
ролик  notice/notice1
ролик  notice/notice2
ролик из videos/subdir2/
ролик  notice/notice1
ролик  notice/notice2

Я эту проблему решил так.
Ролики notices указываются в конфиге в виде массива, таким образом возможно задать последовательность их при формировании плей-листа.
notices : ['disp.mpg', 'mess.mpg'], // объявления
В программе при формировании записи плей-листа в цикле добавляются notices
 // добавление notices
for ( i = 0, len = config.notices.length; i < len; i += 1 ) {
   pl += '\n' + (nStr + (i + 1))  + ',type,0';
   pl +='\n' + (nStr + (i + 1))  + ',filename,' + config.gp26_notice + config.notices[i];
}
Логика такая - зайти в папку videos/ пройтись по всем ее подкаталогам, из каждого случайным образом взять ролик, а при формировании записи в плей-листе для ролика добавлять записи для объявлений.

2. Размер плей-листа.

 Второй вопрос, который надо было решить - размер плей-листа. Поясню. Допустим в videos/ четыре подкаталога 01_tv/, 02_miac/, 03_gp26/, 04_mult/.
Плей-лист формируется раз в сутки и крутиться целый день. При такой структуре каталога плей лист получается примерно таким
MPCPLAYLIST
1,type,0
1,filename,d:/gp26_videos/videos/01_tv/vrachi_13102011.mp4
2,type,0
2,filename,d:/gp26_videos/notice/disp.mpg
3,type,0
3,filename,d:/gp26_videos/notice/mess.mpg
4,type,0
4,filename,d:/gp26_videos/videos/02_miac/obraz_jizni_3.mp4
5,type,0
5,filename,d:/gp26_videos/notice/disp.mpg
6,type,0
6,filename,d:/gp26_videos/notice/mess.mpg
7,type,0
7,filename,d:/gp26_videos/videos/03_gp26/smotrovoi.mpg
8,type,0
8,filename,d:/gp26_videos/notice/disp.mpg
9,type,0
9,filename,d:/gp26_videos/notice/mess.mpg
10,type,0
10,filename,d:/gp26_videos/videos/04_mult/Masha_i_Medved_25.avi
11,type,0
11,filename,d:/gp26_videos/notice/disp.mpg
12,type,0
12,filename,d:/gp26_videos/notice/mess.mpg

Возникла задумка, ведь можно зациклить обход подкаталогов и чем больше повторов, тем больше плей-лист.
Количество повторов вынес в конфиг

numOfRep : 3, // кол-во повторов (сколько в цикле формировать плей-лист с дозаписью)

Реализация логики такая:

// чтобы плей-лист не был слишком коротким, можно увеличить количество повторов
            for ( rep = 0; rep < config.numOfRep; rep += 1 ) {
                // Обойти все подкаталаги и для каждого создать запись в плей-листе
                _.each(subdirs, function (subdir, i) {
                    createRecord(curStrPl, subdir + '/');
                    curStrPl += config.numOfNotices + 1;
                });
            }

 Пока разбирался с решением этих задач немного "причесал" код, сделал его более понятным и прозрачным. Вынес логику записи плей-листа в отдельную функцию.
/**
 *  Запись плей-листа на диск
 */
function recPl () {
    fs.open(config.plDir + config.plName,"w",0644, function (err, file_handle) {
        if ( !err ) {
            fs.write(file_handle, pl, null, 'ascii', function (err, writenn) {
                if (!err) {
                    logger.log('info', 'Playlist ' + config.plName + ' created.');
                }
            });
        } else {
            logger.log('error', 'Record playlist: Error opening file ' + config.plDir + config.plName);
        }
    });
}
Сам проект можно загрузить здесь.

вторник, 6 августа 2013 г.

Задача о 30 птицах

Эта задача из книги "Liber abaci" знаменитого Леонардо Фибоначчи.

Задача. 30 птиц стоят 30 монет. Куропатки стоят по 3 монеты, голуби по 2, а пара воробьев – по монете. Сколько птиц каждого вида?


Решение 1.

Из-за большого количества неизвестных данную задачу вполне логично решать алгебраически. Если число куропаток, голубей и воробьев обозначить буквами x, y, z соответственно, то решение сведется к нахождению тройки натуральных чисел, удовлетворяющих системе уравнений
«Liber аbaci» Леонардо Фибоначчи. Система уравнений 2
3x + 2y + z/2 = 30 умножим на 2. Получим 6x + 4y + z = 60. 
Теперь из 6x + 4y + z = 60 вычтем x + y + z = 30, получим 5x + 3y = 30.
Выразим x = (30 - 3y) / 5; x = 6 - 3/5 y.
Учитывая, что x - целое не отрицательное число, больше 0, то единственное решение, которое удовлетворяет этому условию может быть при y = 5. Тогда x = 3, z = 22.

Решение 2. Димы Зайцева.

Данное решение заключается в использовании следующих логических рассуждений. 
У нас три вида птиц, следовательно 30 делим на 3 и смотрим сколько каждого вида можно купить на 10 рублей.
Тогда куропаток можно купить 3 штуки (остаток 1 руб.), голубей - 5 штук, воробьев 20 штук, а теперь вспомним, что у нас рубль в остатке от куропаток и купим на него еще 2 воробьев.

понедельник, 5 августа 2013 г.

Копия Windows 7 не прошла проверку на подлинность.

Странно было увидеть такое сообщение, учитывая, что винда лицензионная.
Покопался в инете, нашел высказывание, что мол это "глюк" пакета обновлений KB971033. Особо глубоко не стал копать, решил удалить этот пакет.
Необходимо зайти в центр обновления windows
Нажать на ссылку "Установленные обновления"
Далее необходимо найти обновление KB971033 и удалить его.
Чтобы это обновление впредь не устанавливалось необходимо вернуться в центр обновления windows и запустить проверку обновлений.
Когда windows сообщит о доступности новых обновлений, необходимо пройти по ссылке и
снять галочку напротив обновления для проверки подлинности под номером KB971033 и из контекстного меню выбрать скрыть обновление.

Далее я перезагрузил систему, зашел в "Безопасный режим" (F8) и воспользовался средством для удаления активации.
После перезагрузки опять в "Безопасном режиме" тем же средством активировал Windows.
Все.
P.S. Забыл убрать автоматическое обновление и KB971033 установилось снова, так что теперь обновления надо ставить в ручном режиме.

среда, 31 июля 2013 г.

Работа со сканером и отправка электронной почты из C#.

Появилась задача - разработать программу для сканирования документов с возможностью введения данных о пациенте и отправки сканов на заданный email.
Необходимо было обеспечить максимально удобную и интуитивно понятную работу для работников поликлиники.
В итоге интерфейс получился таким:


1.Порядок работы


1.1 Информация о клиенте


Начинать работу необходимо с заполнения информации о клиенте.
Если начинаем работу с первым клиентом после запуска программы, то поля пустые и просто необходимо внести данные.
Если поля содержат данные предыдущего клиента, необходимо нажать кнопку "Следующий" чтобы обнулить значения.
Фамилия, имя, отчество, дата рождения и адрес - являются обязательными к заполнению и программа не разрешит начать сканирование, если какое-то из обязательных полей не заполнено.
Телефон - не обязательное поле и его можно не заполнять.

1.2 Сканирование


Нажатие на кнопку "Сканировать" запускает процесс сканирования. В фоновом режиме создается папка для данного клиента, куда будут сохраняться отсканированные документы. Название папки уникально и имеет следующий вид ГП26_Иванов_И_И_2013_07_26. Таким образом, если Иванов И.И. придет в другой день, то для него будет создана другая папка.
Далее фоново в этой папке создается текстовый файл с данными о клиенте (Иванов_info.txt). 
В процессе сканирования создаются сканы документов, причем, чтобы обеспечить их уникальность в названии скана присутствует порядковый номер (Иванов_И_И_1.jpeg, Иванов_И_И_2.jpeg).

1.3 Отправка почты


По нажатию на кнопку "Отослать" вначале в фоновом режиме создается архив папки клиента созданной в процессе сканирования (ГП26_Иванов_И_И_2013-07-26.7z) , после успешного создания архива происходит отправка электронного сообщения с прикрепленным архивом на заданный email.

2.Особенности реализации


Работать со сканером решил через wia (Windows Image Acquisition).
Нашел обзор сканирования без использования диалогового окна (без диалогового окна быстрее и проще работать) и вынес логику работы со сканером в отдельный класс WIAScanner

Перед отправкой отсканированных изображении на электронный почтовый адрес (класс Email) происходит архивация папки бесплатным архиватором 7-Zip (класс SevenZip).
Сообщение отправляется синхронно, по завершению отправки пользователю выдается соответствующее сообщение.
Некоторые данные (куда отправлять почту) решил хранить во внешнем конфигурационном файле scancenter.config

вторник, 30 июля 2013 г.

Немного о JavaScript. Объекты.

1.2 Объекты.

Объект - это неупорядоченное множество пар ключ-значение.
Часто про объект говорят, что он содержит набор свойств, а если свойство содержит функцию, то его называют методом. Надо понимать, что это просто терминология и по сути это все данные.
Теперь можно сказать, что все в JavaScript является объектами кроме значений "примитивных" типов и это так.
В своей практике я всегда создаю объект с помощью литерала объекта. Это красиво и легко запоминается.
var myObj = {};
Так просто.
Классов в JavaScript нет, но при этом есть механизм прототипов, который позволяет реализовать наследование. Про наследование разговор еще будет впереди.

Для обхода свойств объекта правильно применять цикл for-in ( для массивов лучше for ) .Сразу хочу обратить внимание на одну особенность. Допустим мы расширили прототип Object, от которого наследуют свойства все объекты, а потом создали свой объект pupkin. Теперь мы хотим обойти в цикле свойства созданного нами объекта.
Object.prototype.whoami = "I am Object";

var pupkin = {
    age: 22,
    title: "kursant",
    kurs: 1
};
for (var k in pupkin) {
    console.log( k );   
}
Результат будет
  • "age"
  • "title"
  • "kurs"
  • "whoami"
Это не совсем то, что мы ожидали, но тут ошибок нет. Наш объект унаследовал свойство whoami от своего прототипа. Так что, если необходимо работать со свойствами только одного объекта без учета унаследованных, то необходимо использовать метод hasOwnProperty().
Добавим в цикл условие проверки принадлежности свойства данному объекту и немного модифицируем вывод:
for (var k in pupkin) {
  if (pupkin.hasOwnProperty(k)) {
    console.log( k + ":" + pupkin[k] ); 
  }     
}
Результат:
    • "age:22"
    • "title:kursant"
    • "kurs:1"
Вот, теперь другое дело )
Следующий разговор будет о функциях. Удачи.

воскресенье, 28 июля 2013 г.

Кубанский казачий хор. Песни.

Матушка Добрынюшке наказывала



Матушка Добрынюшке наказывала,
Государыня Добрынюшке наговаривала:
- Ой ты сын мой любезный, свет Деменьтьевич,
Что повесил, кручинясь, буйну голову ?
Ты бы взял в свои ручки белые
Гусли звонкие, сладкогласные.
Стал бы петь да потряхивать кудрями,
Да меня потешать, матерь старую.

- Ты прости, государыня-матушка.
Не поется мне, не играется.
Я вчера скакал по Святой Руси,
Я стрелой летел ниже облака,
Видел я на Руси оскудение,
Видел мерзость кругом запустения,
Церкви белые оскверненные;
Басурманами разоренные.
Басурмане те не из тартара,
А своих кровей, лыком шитые.
Поклоняются люди идолам,
Отреклись от Бога, безумные,
Православную веру забросили,
Обучают детей жить без Господа.
Скоморохам житье - лучше некуда,
Приосанилось племя вертлявое,
Позабыли напевы родимые.
И гудят гудцы непотребное.
Сатана восстал на Святую Русь,
Понаставил бесовские капища,
Из заморских стран едут нехристи
И с собой везут нравы срамные,
Всем заморским Русь заполонили,
Так что духу нет православного.
А князья одну думку думают,
Как без Бога им миром правити.

Матушка Добрынюшке наказывала,
Государыня Добрынюшке наговаривала:
- Ох и глупый ты сын, свет Деменьтьевич,
Не набрался поди уму-разуму.
Не пришла еще ночка темная,
Ночка темная, тьма кромешная.
Есть еще на земле сыны русские,
Православную веру хранящие.
Сколько мучеников, исповедников
Пред Престолом стоят Вседержителя,
День и ночь умоляют с Пречистою
О родной стороне, об Отечестве.
И пока в Церквах Божиих молятся,
Панихиду не правь по Святой Руси.
Матушка Добрынюшке наказывала,
Государыня Добрынюшке наговаривала.

Не для меня



Не для меня придёт весна,
Не для меня Дон разольётся,
И сердце девичье забьётся
С восторгом чувств – не для меня.

Не для меня сады цветут,
В долине роща расцветает,
Там соловей весну встречает,
Он будет петь не для меня.

Не для меня придёт Пасха,
За стол родня вся соберётся,
"Христос воскрес" из уст польётся,
Пасхальный день не для меня.

А для меня кусок свинца,
Он в тело белое вопьётся,
И слезы горькие прольются.
Такая жизнь, брат, ждёт меня.

Немного о javasript. Введение. Типы примитивных значений.

Предисловие.
Не так давно мне посчастливилось пообщаться с хорошими ребятами, которые очень хорошо знают JavaScript. В процессе беседы я понял, что некоторые моменты не очень хорошо понимаю. Цель этой статьи - разобрать некоторые основные моменты в JavaScript ( в первую очередь самому ).

Введение.
Давным-давно (хотя не так уж и давно) в 2008 году, решив стать программистом, я подошел к этому серьезно и решил получить системные знания. Для этого получил высшее образование в области разработки ПО (вечерняя форма), а параллельно с учебой работал программистом. Так вот, диплом я писал на C# и был в легком восторге от платформы .net и конечно в мыслях представлял себя программистом под эту платформу.
Но жизнь вносит свои коррективы, первая моя работа после учебы и переезда в другой город была связана с клиентской разработкой на JavaScript. Признаюсь, что когда я только начал с ним работать, я думал, что это не серьезный язык программирования (до этого я работал с Delphi, PHP, 1С, C#) и поэтому особо не думал о его изучении.
Язык программирования JavaScript на мой взгляд очень дружелюбный, он позволил мне делать довольно серьезные вещи очень поверхностно понимая сам язык. И вот проработав с JavaScript 1 год - плотно и 1 год периодически, я решил навести порядок у себя в голове, восполнить и упорядочить свои знания.
Я благодарен JavaScript за его дружелюбие и глубину, и рад, что он набирает популярность. Конечно, когда планируешь быть программистом на C# - думаешь, блин, это же серьезный язык, его спроектировали серьезные ребята, они изучили кучу языков, выбрали из них лучшее, чтобы этот язык получился самый лучший. Сразу берешь книгу, начинаешь разбираться, писать маленькие программульки, настраиваешься на серьезную работу. А что JavaScript? Да его какой-то гик за 10 дней и ночей написал, вообще странно, что этот язык еще жив и вытеснил из браузеров такого гиганта как Java. Хотя самое первое удивление такое, а что JavaScript - это не Java =-O ?
Тут тебе предлагают разрабатывать на JavaScript. Ну а почему бы и нет? Язык не сложный. Переменные, функции, массивы, объекты, условные операторы, циклы - этого достаточно. Быстренько прочитать обзорную статью, о я понял нужен файл с раcширением js, в него пишешь код и прописываешь путь к этому файлу в html. Хорошо, я согласен. Начинаем работать.
И такое поверхностное отношение к JavaScript очень не справедливо!
Конечно, сейчас он на коне и думаю теперь большинство более основательно подходит к изучению этого языка, но до сих пор попадаются довольно серьезные проекты, в которых код структурирован таким образом:
var ...
var ...
function ...
function ...
function ...
Конечно это все работает, но только понимание сильных сторон языка, знание паттернов и принципов грамотной организации кода могут принести радость от работы на этом языке.
Особенно меня огорчает, когда люди даже и не стремятся разобраться и понять глубже JavaScript (это наверное касается и других вещей).
JavaScript дает мне радость от работы с ним и я хочу вернуть должок и разобрать моменты, которые когда то поверхностно прочитал или не прочитал вовсе. Вперед.

1. Типы дынных.
1.1 Типы примитивных значений.
Когда-то я прочитал такое высказывание, что всё в javascipt является объектами и так мне эта мысль глубоко засела в голову, что потребовалось внимательное разбирательство, чтобы это исправить. Ведь на самом деле в javascript типы делятся на primitive data types (типы примитивных значений) и object.
Итак типы примитивных значений:
  • string;
  • number;
  • boolean (tru, false);
  • undefind;
  • null;
Здесь у меня появился резонный вопрос, а какова их суть? В книжках обычно не разжевывается, что собой представляют primitive data types. Но не надо забывать, что есть спецификация ECMA-262 и там сказано, что значения этих типов в реализации представляются напрямую на низком уровне (дальше я копать не стал). Они не являются объектами, у них нет прототипов и конструкторов (а вот это уже ближе к практическому использованию). Здесь особое внимание стоит уделить типу null из-за особенности работы оператора typeof по отношению к этому типу. А именно, typeof null выдает результат "object" и это сбивает столку, если не знать, что typeof обращается к внутренней таблице, где почему то для null прописано возвращать "object". Хотя на самом деле надо бы возвращать null, так как это и есть правда.
Хотелось бы прояснить еще один момент относительно "примитивных" типов. Значения этих типов не имеют свойств и методов, но как же тогда объяснить такое поведение строкового литерала.
  • "Pupkin".length
  • 6
Дело тут в том, что в JavaScript для чисел, строк и логических значений существуют объекты-обертки. Объекты-обертки обладают рядом разнообразных свойств и методов, которые делают работу с "примитивными" типами более удобной. На самом деле этот не идет вразрез с определением "примитивных" типов. Просто интерпретатор при передаче ему выражения
  • "Pupkin".length
 за кулисами временно создает объект из строки (new String("Pupkin")) вызывает метод length у этого объекта, а результат возвращается в виде строки. Конечно с точки зрения человека, создается ложное ощущение, что примитив строки имеет метод lenght.
Удачи!

понедельник, 22 июля 2013 г.

Скрипт выбора провайдера на powershell

Итак, появилась необходимость быстро менять настройки сети. Решил создать скрипт на powershell, который позволил бы быстро менять сетевые настройки. Скрипт выставляет сетевые настройки в зависимости от указанного в параметрах провайдера при запуске. Вот исходник set_provider.ps1.
$provider = $args[0]
#вывод справочной информации
function printHelp {
    "ИМЯ"
    "`tset_provider"
    "ОПИСАНИЕ"
    "`tЗадает сетевые настройки для указанного провайдера"
    "`n"
    "-------------------------- Пример 1 --------------------------"
    ""
    ".\set_provider.ps1 meriya"
    "`n"
    "Описание"
    "-----------"
    "Эта команда переключает сетевые настроки на сеть мэрии"
    "`n"
    "-------------------------- Пример 2 --------------------------"
    ""
    ".\set_provider.ps1 sibsety"
    "`n"
    "Описание"
    "-----------"
    "Эта команда переключает сетевые настроки на сеть сибирских сетей"
    "`n"
    "-------------------------- Пример 3 --------------------------"
    ""
    ".\set_provider.ps1 enforta"
    "`n"
    "Описание"
    "-----------"
    "Эта команда переключает сетевые настроки на сеть энфорты"
}
$wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'"
#задать настройки сети для выбранного провайдера
switch ($provider) {
    "meriya" {
        $wmi.EnableStatic("10.190.130.244","255.255.255.0")
        $wmi.SetGateways("10.190.130.1",1)
        $wmi.SetDNSServerSearchOrder("10.195.9.71")
        "Заданы сетевые настройки сети мэрии."
    }
    "sibsety" {
        $wmi.EnableStatic("192.168.1.244","255.255.255.0")
        $wmi.SetGateways("192.168.1.2",1)
        $wmi.SetDNSServerSearchOrder("192.168.1.2")
        "Заданы сетевые нстройки сибирских сетей."
    }
    "enforta" {
        $wmi.EnableStatic("10.171.72.244","255.255.255.0")
        $wmi.SetGateways("10.171.72.1",1)
        $wmi.SetDNSServerSearchOrder("8.8.8.8")
        "Заданые сетевые настройки энфорты."
    }
    "h" {printHelp}
    default {Write-Output "Нужны параметры! Для справки вызови set_provider.ps1 h"}
}

воскресенье, 30 июня 2013 г.

Формирование плей-листа на nodeJS

В поликлинике, где я работаю, установлено информационное табло.


Его установили с целью демонстрации роликов с сайта МЗНСО (www.miac-nso.ru). Мы решили немного развить эту идею и показывать ролики передач о здоровье, свои ролики, мультики и объявления. Таким образом была поставлена задача - каждый день показывать новый видеоряд роликов. Вот условия, предъявленные к показу роликов:
  1. Ролики распределяются по группам
    1. Передачи о здоровье
    2. Ролики с сайта МЗНСО
    3. Реклама смотрового кабинета
    4. Мультики (смешарики, лунтик, Маша и медведь)

  1. Все это чередовать одно с другим и зациклить по кругу
  2. После каждого ролика - показ объявлений поликлиники.


Таким образов плей-лист должен формироваться каждый день и выглядеть так:

передача о здоровье
объявления
ролик с сайта МЗНСО
объявления
ролик поликлиники (реклама смотрового)
объявления
мультик
объявления

Первой мыслью было использовать powershell, но немного подумав, я решил использовать nodeJS.
Идея в принципе простая - для каждой группы роликов создать свою директорию, потом программно пробегать по этим директориям в заданном порядке, брать из каждой директории случайным образом название ролика и вставлять запись о нем в playlist.

В итоге получилась такая структура каталогов:
notice - содержит видео с объявлениями
videos - группы роликов. Название каждой группы начинается с цифры для того, чтобы управлять порядком этих роликов в плей-листе (сначала ролик из папки 01_tv, потом из 02_miac и т.д.)
Сам плей-лист лежит в папке gp26_videos.
В качестве проигрывателя решил использовать media player classic home cinema (http://mpc-hc.org/).
В документации к плееру написано как вызвать плеер из командной строки с указанием плей-листа и задать полноэкранный режим показа (mpc-hc.exe /fullscreen /play dir/playlist.mpcpl).
Эта система будет работать в window 7, так что необходимо было средствами системы организовать поочередное выполнение следующий действий.
  1.  Запуск программы для формирования плей-листа.
  2. Запуск проигрывателя с новым плей-листом.
Эта задача была решена с использованием двух скриптов на powershell и двух задач, созданных в планировщике заданий windows, которые последовательно выполняются раз в день с утра и вызывают скрипты. Первый скрипт - вызывает программу nodeJS, которая формирует плей-лист. Второй скрипт - вызывает плеер и передает ему созданный плей-лист.
Единственное - надо разрешить выполнение скриптов powershell. Для этого - запустить под админом powershell  и выполнить set-executionpolicy remotesigned.

Система получилась достаточно гибкая видео можно добавлять динамически, только надо соблюдать правила наименования роликов (нужно использовать только латинские буквы). Можно создавать новые каталоги с роликами и они будут участвовать в формировании плей-листа.
Основные параметры для программы формирования плей-листа я вынес в конфигурационный файл. Вот его содержание:
module.exports = {
    // где находятся подкаталоги с видео
    video_dir   : 'd:/gp26_videos/videos/',
    //где находится видео с объявлениями
    gp26_notice : 'd:/gp26_videos/notice/mess.mpg',
    // где находится плей-лист
    plDir       : 'd:/gp26_videos/'
}
Так же используется логирование для слежения за работой программы формирование плей-листа и фиксации ошибок.
Вот код программы формирования плей-листа:
var fs = require('fs');
var sys = require('sys');
var _ = require('underscore');
var winston = require('winston');
var logger = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: 'log/pl.log' })
    ]
});
var config = require('config');
var pl = "MPCPLAYLIST";
var curStrPl = 0;
/**
 * Создает запись в плей листе
 * @param nStr номер записи в плей-листе
 * @param subDir название директории
 * @param callback
 */
function createRecord (nStr, subDir, callback) {
    //1,filename,D:\gp26_videos\tv\vrachi_03102011.mp4
    fs.readdir(config.video_dir + subDir, function (err, files) {
        if (!err) {
            pl += '\n' + nStr + ',type,0';
            pl += '\n' + nStr + ',filename,' + config.video_dir + subDir + files[_.random(0, files.length - 1)];
            pl += '\n' + (nStr + 1)  + ',type,0';
            pl +='\n' + (nStr + 1)  + ',filename,' + config.gp26_notice;
                callback(nStr);
        } else {
            logger.log('error', 'Create record: Error of ' + config.video_dir + subDir + ' read dir');
        }
    });
}

function createPl () {
    fs.readdir(config.video_dir, function (err, subdirs) {
        if (!err) {
            // Обойти все подкаталоги и для каждого создать запись в плей-листе
            _.each(subdirs, function (subdir, i) {
                curStrPl++;
                var nStr =  i + curStrPl;
                createRecord(nStr, subdir + '/', function (n) {
                    // Запись плей-лист на диск
                    if ((n + 1) === (subdirs.length * 2)) {
                            plName = 'playlist_gp26.mpcpl';
                        fs.open(config.plDir + plName,"w",0644, function (err, file_handle) {
                            if ( !err ) {
                                fs.write(file_handle, pl, null, 'ascii', function (err, writenn) {
                                    if (!err) {
                                        logger.log('info', 'Playlist ' + plName + ' created.');
                                    }
                                });
                            } else {
                                logger.log('error', 'Record playlist: Error opening file ' + config.plDir + plName);
                            }

                        });
                    }

                });
            });
        } else {
            logger.log('error', 'Create playlist: Error of ' + config.video_dir + ' read dir');
        }
    });
}
createPl();