scripts

пятница, 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 установилось снова, так что теперь обновления надо ставить в ручном режиме.