Как мы уже не раз говорили, эта книга предназначена для программистов, участвующих в большом Флэш-проекте. Однако все большие проекты отличаются тем, что необходимо прикладывать много усилий для поддержания порядка в них. Обычно требуется заводить центральное хранилище исходных файлов, принимать меры к повторному использованию кода, грамотно применять статическую и динамическую линковку, иметь средства для автоматической сборки версий и т.д. Удастся ли навести подобный порядок во Флэш-проекте и может ли Flash МХ предоставить для этого необходимые средства? Этому вопросу и посвящена данная лекция. И начнем мы с возможностей повторного использования кода.
Повторное использование кода - это первое, зачем в большом Флэш-проекте нужен программист. То есть, ряд компонентов должен быть написан заранее и использоваться всеми участниками проекта. Здесь обычно не возникает вопросов до тех пор, пока в компонентах не возникает ошибок. А вот дальше начинаются мучения. Несчастный программист рассылает всем письмо: "Вот в таком-то файле лежит исправленный компонент (или просто клип), откройте его и перетащите в разрабатываемый вами модуль". А несчастный дизайнер, который по пять раз на дню проделывает эту операцию, кроет программиста последними словами. Или же забывает (забивает?) сию операцию проделывать. А потом через три дня снова кроет программиста, за то, что "ничего не работает". Знакомая ситуация? Совсем другое дело, когда в каком-нибудь Java или C++ проекте можно указать, где лежит библиотечный исходный файл. И когда разработчик
Итак, если для символа
Если в символ вставлены экземпляры других символов, они тоже "высасываются" из внешнего файла (не зависимо от того, установлен ли непосредственно для них режим
Обратите внимание: если у вас в каком-нибудь клипе, который вы хотите подменять с помощью , помните, что те символы, которые вы создаете с помощью , не будут заменены автоматически. Можно для каждого из них настроить в данном клипе. Тогда они всегда будут импортироваться вместе с главным клипом.
В каком-то смысле механизм #include, за исключением того, что #include позволяет загрузить только кусок кода ActionScript, а с помощью #include " этой же лекции).
Сразу хочется заметить, что термин
Итак, что можно сделать с помощью этой области source:
disabled, это значит, что Флэш не знает никакого другого "источника" для данного символа, кроме его локальной библиотечной копии (нажав кнопку Browse, можно указать этот источник). Вот теперь замена символа будет производиться при каждой компиляции ролика.В целом механизм
Первая проблема связана с использованием "многозвенного" А содержит в себе символ B, при этом символ А во всех флэш-роликах обновляется из файла А, а символ B во всех флэш-роликах (в том числе в файле А ) обновляется из файла B.
При наличии такой конфигурации A, он "падает" каждый раз с ошибкой "
Вторая проблема связана с тем, что при обновлении author time shared символов, которые лежат в подпапках core, то возможно создание папок core copy, core copy (1), core copy (2) и т. п., причем при каждой следующей компиляции создается новая папка.
Это может вылиться в раздувание файлов, и, кроме того, привести к использованию неправильных версий символов. Как решить эту проблему нормальным способом - неизвестно. Единственное, что можно предложить - это не использовать папки в библиотечном файле, то есть рекомендуется складывать компоненты прямо в корневую папку
Аналогов
Преимущества данного подхода очевидны: не нужно перекомпилировать ролик для того, чтобы обновить некоторые библиотечные компоненты, вы просто заменяете один или несколько библиотечных *.swf-файлов, и все работает. Данный подход обладает теми преимуществами перед альтернативными (например, использование loadMovie ), что всю работу по загрузке внешнего кода берет на себя флэш-плеер.
Иногда без этого даже нельзя обойтись, например, в тех случаях, если вы хотите, чтобы ваши флэш-ролики поддерживали сменные скины, и при этом используете разработанные не вами контролы пользовательского интерфейса, которые скины не поддерживают. В таком случае вы можете просто настроить для всех символов-элементов
Во Flash MX
Управление параметрами
Итак, вам нужно задать идентификатор (тот же самый идентификатор, что нужен для использования символа из ActionScript), поставить одну из двух галочек ( Export for runtime sharing, Import for runtime sharing ) и заполнить поле URL именем *.swf-файла, из которого будет производиться импорт символа.
Удобно настроить эти параметры для экпорта, в том числе URL, в библиотечном файле, а из него просто перетаскивать библиотечные символы в клиентские флэш-ролики. Тогда в последних останется правильно заполненным поле URL, а галочка Export for runtime sharing автоматически превратится в галочку Import for runtime sharing.
Во Flash MX больше нигде (кроме вышеописанного места) нельзя настроить что-то, относящееся
Из ActionScript тоже нет никакой возможности управлять настройками
Если совершенно необходимо держать под контролем то, что происходит при динамической загрузке повторно используемых компонентов, лучше отказаться от употребления loadMovie.
Обсудим детальнее, какие неприятности могут вас ожидать при использовании
BASE ) из следующей лекции).Для каждой флэш-платформы (имеется в виду OS + Browser) существует один "стандартный" способ задания библиотечного файла в поле URL. К счастью, для большинства платформ эти способы одинаковы и выглядят так: <имя файла>.swf. Есть и исключения, например, для Internet Explorer на MacOS это file:///<полный путь к *.swf-файлу>.
Если вы укажете URL к *.swf-файлу "нестандартным" для данной платформы способом, то при каждом использовании импортируемых символов флэш-плеер будет загружать их в память заново (по предположениям авторов, флэш-плеер сравнивает путь, прописанный в поле URL, c путем, возвращенным ему платформой, и загружает символ повторно, если пути не совпадают с точностью до символа)! Поэтому ничего не стоит написать флэш-ролик, который через 5 минут своей работы съест всю свободную оперативную память. С этим нужно быть очень аккуратным.
Вы спросите: "А как же написать флэш-ролик, работающий корректно в ситуациях с разными флэш-платформами" (в том смысле, что у них разные "стандартные" способы записи URL)? Авторам известен только один способ: нужно полностью динамически сгенерировать все содержимое тегов <OBJECT> и <EMBED> с помощью JavaScript, в котором выясняется тип браузера и, в зависимости от типа браузера, подставить нужное значение атрибута BASE тегам <OBJECT> и <EMBED> (см. также раздел "Изменение текущей директории" (атрибут BASE ) из следующей лекции).
А загружается из файла А.swf, а в клипе А лежит клип B, который загружается из файла B.swf и так далее. Во флэш-плеере до версии 6.0.65.0 была довольно условная поддержка этой функциональности, что выражалось в падениях флэш-плеера вместе с браузером (правда, Macromedia и не обещала, что это будет работать). Начиная с версии 6.0.65.0 во флэш-плеере официально добавлена поддержка "многозвенного" При использовании
В каждый *.swf-файл, из которого импортируются символы, нужно положить один дополнительный пустой символ и настроить ему такие же параметры
Это действие приводит к нужному результату: похоже, что в таком случае весь *.swf-файл загружается заранее, после чего все другие определенные в нем символы можно использовать без проблем.
Представьте себе такую ситуацию. Вы выкладываете свой готовый, протестированный проект на удаленный сервер и видите, что ничего не работает. По крайней мере, при первом открытии веб-страницы, потому что после нажатия Refresh все, скорее всего, загрузится нормально.
В чем же дело?
Видимо, произошла "рассинхронизация" разных клипов. Не забывайте, что каждый клип живет своей жизнью. Пока все файлы лежали в локальной сети, порядок выполнения кода был один, а после того, как файлы положили в Интернет, - он изменился.
Например, код в уже загруженных клипах "убежал" вперед и выполнился до выполнения кода еще не загруженных клипов, хотя планировалось все наоборот.
Чтобы решить эту проблему, нужно как-то отследить момент загрузки всех клипов, и только после этого начать выполнять нужный код. Как это сделать?
У runtime-shared модулей есть такое свойство: пока модуль (*.swf) полностью не загрузится, никакие клипы в нем играть не начнут. Этим можно воспользоваться.
Создадим в каждом из *.swf-модулей по пустому символу, в каждом из которых поместим приблизительно такой код:
if (_global.swfModulesCounter == undefined) _global.swfModulesCounter = 0; global.swfModulesCounter++;
Этот код увеличивает счетчик загруженных .swf-модулей на единицу.
Теперь можно поместить в отдельной сцене флэш-ролика все эти пустые символы, а в нужном месте (в котором и предстоит ожидать загрузки всех модулей) сделать трехкадровый цикл с проверкой значения счетчика. Если оно достигло общего числа нужных *.swf-модулей - значит, можно продолжать выполнение.
Выше мы рассмотрели возможности применения
Теперь приведем два примера, когда может быть полезно использовать оба механизма совместно.
Представьте себе такую ситуацию: вы используете только library, а в тот же каталог, в котором лежат все флэш-ролики.
Что делать?
Об этом нужно побеспокоиться заранее. Для всех компонентов, с которыми вы используете
Правда, по имеющейся у авторов неприятной статистике, что в сложных случаях данный механизм срабатывает лишь на 90%, в остальных случаях сами символы меняются, а параметры
Насколько известно авторам, во Флэш МХ не существует другого сколько-нибудь приемлемого
Рассмотрим теперь такую ситуацию. У нас есть несколько флэш-проектов, каждый из которых использует часть библиотечных компонентов, загружаемых с помощью
Но в одном проекте нам нужна одна часть библиотечных компонентов, а в другом - другая. Тем не менее, все флэш-ролики созданы на базе одного и того же
Кроме того, мы знаем, что если во Флэш МХ на сцену положен хоть один символ, который импортируется с помощью
Что же делать?
Вручную заходить в каждый флэш-ролик и удалять соответствующий
Есть лучшее решение: положить все
Это же решение можно (и нужно) применить к контролируемой загрузке клипов (см. выше в этой лекции): регулировать количество счетчиков в зависимости от действительно необходимого числа *.swf-модулей с помощью группирующего клипа.
Как мы видели, использовать механизмы sharing часто бывает удобно, однако это сопряжено и с рядом неприятностей. Если вам нужно всего лишь определить несколько функций (или классов) для общего пользования, то есть ничего кроме кода на ActionScript не нужно делать, проще воспользоваться инструкцией #include.
Если в рамках проекта создается много похожих флэш-роликов, то, даже если они используют общие компоненты, в каждом ролике отдельно придется сделать много сходных действий.
Чтобы избежать этого, можно использовать
Рассмотрим в качестве примера кое-какие вещи из тех, что могут лежать в
Первое, что вы, вероятно, захотите увидеть в
Скорее всего, вы применяете
Если во всех флэш-роликах вы пользуетесь какими-то общими функциями и классами, вполне можно сразу подключить эти #include -файлы в
Возможно, лучше подключение всех #include -файлов сгруппировать в клипе (опять-таки, author time shared ), чтобы всегда можно было добавить или удалить какой-то из них централизованно.
Вы помните, что для корректной работы runtime-shared компонентов необходимо сделать специальную процедуру (см. ранее в этой лекции).
Авторы предлагают выделить для этой цели в
Чтобы сделать сцену, откройте панель Scene ( Shift-F2 ) и нажмите на кнопку с изображением плюса. Сцены можно менять местами с помощью перетаскивания их мышью.
Авторы предлагают выделить в
Вероятно, что в процессе загрузки всех флэш-роликов можно будет выделить некоторые шаги, связанные с выполнением каких-то команд.
Например:
//скрытие всего _root'а (пока идет загрузка);
_root._visible = false;
// ожидание в трехкадровом цикле, пока не загрузятся всe
// .swf-модули (см. ранее в этой лекции);
if (_global.SWFModulesLoaded < _global.TOTAL_SWF) gotoAndPlay (2);
//применение нужных стилей ко всем контролам, которые теперь
// уже успели загрузиться;
_global.locTextStyleFormat.applyChanges(); //
_global.btnTextStyleFormat.applyChanges(); //
//посылка каких-то внутренних управляющих событий;
this.raise("InitializationComplete", "InitializationComplete",
EVT_TYPE_STRING);
this.raise("ModelInitializationComplete",
"ModelInitializationComplete", EVT_TYPE_STRING);
//обработка XML-скриптов;
if (_global.iniFileParams.xmlSetupString != undefined)
_global.ext.importFromXml(_global.iniFileParams.xmlSetupString);
_global.ext.sendRestoreStateEvent();
}
//открывание всего _root'а (все загружено);
_root._visible = true;
//остановка главного клипа
stop();
Все подобные действия нужно проделывать в
Иногда в сложных
Во Flash MX есть очень полезная вещь -
Зачем это нужно?
<OBJECT> и <EMBED> с необходимыми параметрами с помощью JavaScript (ранее в этой лекции упоминалось, для чего это может быть нужно). Напомним, что тег <OBJECT> (с соответствующим параметром CLSID ) служит для демонстрации флэш-ролика в Internet Explorer, а <EMBED> - (с соответствующим MIME-type) в браузерах, основанных на технологии Mozilla (собственно Mozilla, Netscape или Firefox).Во-первых, нужно создать HTML-файл, содержащий нужный вам код, параметризовав его специальными шаблонными переменными (см. далее).
Во-вторых, нужно положить этот файл в папку C:\Program Files\Macromedia\Flash MX\First Run\HTML (или аналогичную). Кстати, там же можно посмотреть примеры
И, в-третьих, нужно перезапустить Flash MX, после чего этот
Пусть вы редактируете $MO. Когда Флэш при $WI и $HE ) нужно вставить в тех местах, где указываются ширина и высота флэш-ролика.
Все шаблонные переменные начинаются со знака ' $ ' (если вам нужно будет вставить просто символ доллара, перед ним нужно будет поставить ' \ '), после которого следуют две большие латинские буквы, идентифицирующие переменную.
Ниже мы перечислим наиболее употребительные переменные
Самые нужные переменные
| Название шаблонной переменной | Код | Пояснение |
|---|---|---|
| Заголовок |
$TT |
Строчка, указанная после этой переменной будет показываться в комбо-боксе выбора |
| Начало описания |
$DS |
Описание |
| Конец описания |
$DF |
См. предыдущий комментарий. |
| Имя файла флэш-ролика | $MO |
Например, mymovie.swf. |
| Заголовок ролика | $TI |
Например, mymovie (то же, что $MO, но без расширения). |
| Ширина ролика | $WI |
В пикселах. |
| Высота ролика | $HE |
В пикселах. |
| Цвет фона | $BG |
Цвет, установленный в качестве дефолтового в вашем ролике (устанавливается в диалоге Modify / Document ). |
| Качество изображения | $QU |
Качество перевода векторной графики в изображения растровую в плеере (задается в закладке HTML диалога Publish Settings ). |
Параметры тега <EMBED> |
$PE |
Генерирует сразу несколько стандартных параметров тега <EMBED>: src (имя файла флэш-ролика), bgcolor (цвет фона) и quality (качество перевода векторной графики в растровую). |
Параметры тега <OBJECT> |
$PO |
Генерирует сразу несколько стандартных параметров тега <OBJECT>: movie (имя файла флэш-ролика), bgcolor (цвет фона) и quality (качество перевода векторной графики в растровую). |
Если вы собрались написать свою
Приведем соображения авторов по поводу устройства
Состав
loadMovie ).На любом уровне (будь то #include -файлы, *.fla-файлы или *.swf-файлы) очень полезно соблюдать модульность, то есть помещать все компоненты в отдельные файлы. Тогда вы всегда сможете без особых проблем сконфигурировать
Мы пока ни словом не обмолвились о том, где удобно хранить эти файлы (понятно, что это все имеет значение, только если вы пользуетесь механизмом
Из опыта авторов следует, что удобнее всего хранить эти библиотечные файлы на каком-нибудь подключаемом диске, например, М:. Допустим, у вас есть один библиотечный файл: library.fla. Тогда во всех флэш-роликах (то есть, в M:\library.fla. Это очень удобно тем, что вы в любой момент можете использовать нужную версию M:. Например, для разработчиков флэш-роликов этот диск может ссылаться на \\myserver\myshare\FlashMXLibrary, а для разработчиков библиотечных компонентов - ссылаться на C:\FlashMXLibrary\TheLatestTestVersion.
Теперь вспомните, в разделе, посвященном
Дело в том, что Flash MX ведет себя каким-то странно-интеллектуальным образом с путями, заданными в области source свойств символа (собственно, с настройками путей
M:M:M: (а не соответствующий этому сетевой или какой-нибудь еще путь).Представьте себе, что у вас есть большой проект с большим количеством не очень сложных флэш-роликов, которые должны быть достаточно "легкими", не требовать никаких дополнительных файлов для своей загрузки (весь флэш-ролик в одном *.swf-файле).
Но все-таки есть некоторые вещи, которые вы хотите менять одним махом во всех этих флэш-роликах, например, какие-то цвета, язык или что-нибудь еще.
Понятно, что в этом случае очень неудобно каждый раз вручную перекомпилировать все 50 флэш-роликов, особенно это чревато соблазном сохранять результаты прошлых компиляций, а это, в свою очередь, опасно тем, что некоторые последние изменения могут не попасть в сборку.
Именно для такого проекта "
Как же работает наш
ShellExecute() ;Ниже приведен откоментированный код этого
Фактически, наша программа просто делает вид, что пользователь открыл некоторый файл во Флэш МХ и выбрал из меню пункт File / Publish или пункт Control / Test Movie. Чтобы воспользоваться этим " compile или publish. Во втором случае будет произведена
#include "stdafx.h"
#define WINVER 0x0500
// чтобы можно было использовать функции Windows 2000
#include "windows.h"
#include "winuser.h"
#include "shellapi.h"
int main(int argc, char* argv[])
{
const int PUBLISH_MENU_ID = 40057;
// Номера получены из MSSPY
const int COMPILE_MENU_ID = 33371;
// с помощью этой утилиты были определены
const int CLOSE_CHILD_ID = 57602;
// идентификаторы интересующих нас пунктов меню
const int SAVE_ID = 57603;
if (argc != 3) {
// проверка на корректность исходных значений
puts ("First parameter: full .fla file name to compile,");
puts ("Second parameter: \"publish\" or \"compile\"");
return 0;
}
int MENU_ID = (!strcmp (argv[2], "publish")) ? PUBLISH_MENU_ID :
COMPILE_MENU_ID;
// в зависимости от пожеланий пользователя либо компилируем
// (ctrl-Enter), либо публикуем (ctrl-F12)
char buffer[200] = "Macromedia Flash MX - [";
char buffer1[200] = "Macromedia Flash MX - ";
// два варианта заголовка окна: иногда бывает так, а иногда иначе
char tmpbuf[200] = "";
char one[2] = " ";
for (int i = 0; i < strlen (argv[1]); i++) {
// формируем возможные названия окон
if (argv[1][i] == '\\') {
strcpy (tmpbuf, "");
continue;
}
else {
one[0] = argv[1][i];
strcat (tmpbuf, one);
}
}
strcat (buffer, tmpbuf);
strcat (buffer1, tmpbuf);
strcat (buffer, "]");
LPCSTR window_name = (LPCSTR) buffer;
//сформировали заголовки
LPCSTR window_name1 = (LPCSTR) buffer1;
WORD low = (WORD)MENU_ID,
// младший байт - идентификатор меню,
// старший должен быть равен 1.
high = 1; //accelerator
char param[400];
strcpy (param, "\"");
strcat (param, argv[1]);
strcat (param, "\"");
printf ("%s\n", param);
puts ("Trying to open file");
//открываем нужный *.fla-файл
ShellExecute (0, "open", param, NULL, NULL, SW_SHOW);
HWND h = 0, h1 = 0;
puts ("Trying to find the main window");
do {
Sleep (100);
h = FindWindow ("SmartSketchMDIFrame", window_name);
//ищем окно
h1 = FindWindow ("SmartSketchMDIFrame", window_name1);
} while (!h !h1);
if (!h) h = h1; //нашли одно или другое окно
puts ("Sending commands");
// посылаем сообщение о компиляции или публикации
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
//сейчас мы закроем все ненужные окна
low = (WORD)CLOSE_CHILD_ID;
puts ("Closing child windows");
if (MENU_ID == COMPILE_MENU_ID)
// если была компиляция, то закрываем это окно
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
low = (WORD)SAVE_ID;
// сохраняем файл
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
// полностью закрываем сhild-окно.
// SendMessage работает синхронно, а PostMessage -
// асинхронно. Здесь можно использовать PostMessage(), потому
// для продолжения работы ничего дожидаться не нужно.
low = (WORD)CLOSE_CHILD_ID;
PostMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
//пробуем отыскать диалоговое окно
HWND hMain = 0, hDialog = 0;
puts ("Searching for the dialog boxes");
do {
// ищем диалог о сохранении файла, который, возможно,
// появился как результат выполнения команды закрытия окна.
hMain = FindWindow ("SmartSketchMDIFrame", "Macromedia Flash MX");
if (hMain) {
puts ("There were no dialog");
break;
}
hDialog = FindWindow (NULL, "Flash MX");
if (hDialog) {
high = BN_CLICKED;
low = IDNO;
SendMessage (hDialog, WM_COMMAND, MAKEWPARAM(low, high), NULL);
//закрываем диалог
break;
}
Sleep (100);
} while (true);
printf ("Main = %Xh, Dialog = %Xh\n", h, hDialog);
return 0;
}
subst - исключительно полезная утилита для создания виртуальных дисков, которые, как уже упоминалось, очень удобно использовать в качестве места размещения файлов-источников для subst является функция Map Network Drive, доступная из Windows Explorer.
Синтаксис:
subst <drive>: <directory> для создания виртуального диска;subst <drive>: /d для удаления виртуального диска. При выполнении этой команды убедитесь, что текущая директория не лежит на виртуальном диске.Жесткие ссылки ( library. Вы можете организовать автоматическое обновление символов в library или файлы, лежащие в нем. Вот для этого как раз и служат жесткие ссылки: эти файлы можно залинковать на сетевой диск, и они будут обновляться автоматически.
Есть программы, которые позволяют это делать, например, Far 1.5 ( Alt-F6 ). Обязательное условие: все ссылки должны лежать в одном томе NTFS, то есть дизайнеры флэш-роликов не могут держать свои каталоги для разработки на локальных дисках.
Обычно
Разработка флэш-проектов здесь абсолютно не является исключением. Поэтому рассмотрим некоторые аспекты этой проблемы более подробно.
Существуют разные
Подробно рассматривать достоинства и недостатки каждой из них мы не станем, а примеры, приводимые ниже, будут касаться MS VSS, потому что именно ею мы пользовались для управления одним из флэш-проектов.
Выбор был сделан вполне тривиально: MS Visual SourceSafe - это наиболее простая система. Правда, позже мы обнаружили, что MS VSS очень хорошо подходит для флэш-проектов. Например, в ней по умолчанию запрещены multiple checkouts (которые не имеют смысла при работе с двоичными файлами *.fla), а также есть очень удобные инструменты links и shadow folders, о которых мы расскажем далее.
Что для флэш-проектов является характерным - так это то, что исходные файлы имеют двоичный формат, что отнюдь не способствует совместной работе над ними и последующему слиянию ( merge ) файлов. Что ж, тем жестче нужно ограничивать одновременные изменения .fla-файлов (и запрещать unreserved, или multiple, check-outs ).
MS VSS по умолчанию и работает в таком режиме.
Разумно также (как уже неоднократно замечалось ранее) выносить максимум кода за рамки *.fla-файлов (в include -файлы). Тогда можно настроить возможность одновременной работы над этими файлами.
При интеграции очень удобно пользоваться такими механизмами (или их аналогиями), как ссылки ( links ) и теневые папки ( shadow folders ), которые есть в VSS.
Ссылки VSS - это аналог жестких ссылок (
Приведем пример. Предположим, вы изменили файл core.fla и выполнили check-in (внесли изменения). Поскольку на core.fla существуют ссылки в проектах $/core/ и $/author-shared, он изменился сразу в двух проектах. У проекта $/core/ настроен shadow folder в \\myshare\myProject\src (здесь под \\myshare имеется в виду абстрактный сетевой путь, являющийся корнем для флэш-проектов), а у проекта $/author-shared - в \\myshare\\myProject\author-shared, в результате чего файл изменился сразу в двух каталогах: в архивном каталоге проекта ( src ) и каталоге, который подключен в качестве сетевого диска (например, как M:) и из которого обновляются все флэш-ролики при компиляции ( author-shared ).
Точно так же с помощью links и shadow folders можно обновлять *.swf-файлы, причем если вы еще используете жесткие ссылки в файловой системе, то *.swf-файлы могут автоматически обновиться в рабочих директориях дизайнеров.
Как мы уже не раз говорили, эта книга предназначена для программистов, участвующих в большом Флэш-проекте. Однако все большие проекты отличаются тем, что необходимо прикладывать много усилий для поддержания порядка в них. Обычно требуется заводить центральное хранилище исходных файлов, принимать меры к повторному использованию кода, грамотно применять статическую и динамическую линковку, иметь средства для автоматической сборки версий и т.д. Удастся ли навести подобный порядок во Флэш-проекте и может ли Flash МХ предоставить для этого необходимые средства? Этому вопросу и посвящена данная лекция. И начнем мы с возможностей повторного использования кода.
Повторное использование кода - это первое, зачем в большом Флэш-проекте нужен программист. То есть, ряд компонентов должен быть написан заранее и использоваться всеми участниками проекта. Здесь обычно не возникает вопросов до тех пор, пока в компонентах не возникает ошибок. А вот дальше начинаются мучения. Несчастный программист рассылает всем письмо: "Вот в таком-то файле лежит исправленный компонент (или просто клип), откройте его и перетащите в разрабатываемый вами модуль". А несчастный дизайнер, который по пять раз на дню проделывает эту операцию, кроет программиста последними словами. Или же забывает (забивает?) сию операцию проделывать. А потом через три дня снова кроет программиста, за то, что "ничего не работает". Знакомая ситуация? Совсем другое дело, когда в каком-нибудь Java или C++ проекте можно указать, где лежит библиотечный исходный файл. И когда разработчик
Итак, если для символа
Если в символ вставлены экземпляры других символов, они тоже "высасываются" из внешнего файла (не зависимо от того, установлен ли непосредственно для них режим
Обратите внимание: если у вас в каком-нибудь клипе, который вы хотите подменять с помощью , помните, что те символы, которые вы создаете с помощью , не будут заменены автоматически. Можно для каждого из них настроить в данном клипе. Тогда они всегда будут импортироваться вместе с главным клипом.
В каком-то смысле механизм #include, за исключением того, что #include позволяет загрузить только кусок кода ActionScript, а с помощью #include " этой же лекции).
Сразу хочется заметить, что термин
Итак, что можно сделать с помощью этой области source:
disabled, это значит, что Флэш не знает никакого другого "источника" для данного символа, кроме его локальной библиотечной копии (нажав кнопку Browse, можно указать этот источник). Вот теперь замена символа будет производиться при каждой компиляции ролика.В целом механизм
Первая проблема связана с использованием "многозвенного" А содержит в себе символ B, при этом символ А во всех флэш-роликах обновляется из файла А, а символ B во всех флэш-роликах (в том числе в файле А ) обновляется из файла B.
При наличии такой конфигурации A, он "падает" каждый раз с ошибкой "
Вторая проблема связана с тем, что при обновлении author time shared символов, которые лежат в подпапках core, то возможно создание папок core copy, core copy (1), core copy (2) и т. п., причем при каждой следующей компиляции создается новая папка.
Это может вылиться в раздувание файлов, и, кроме того, привести к использованию неправильных версий символов. Как решить эту проблему нормальным способом - неизвестно. Единственное, что можно предложить - это не использовать папки в библиотечном файле, то есть рекомендуется складывать компоненты прямо в корневую папку
Аналогов
Преимущества данного подхода очевидны: не нужно перекомпилировать ролик для того, чтобы обновить некоторые библиотечные компоненты, вы просто заменяете один или несколько библиотечных *.swf-файлов, и все работает. Данный подход обладает теми преимуществами перед альтернативными (например, использование loadMovie ), что всю работу по загрузке внешнего кода берет на себя флэш-плеер.
Иногда без этого даже нельзя обойтись, например, в тех случаях, если вы хотите, чтобы ваши флэш-ролики поддерживали сменные скины, и при этом используете разработанные не вами контролы пользовательского интерфейса, которые скины не поддерживают. В таком случае вы можете просто настроить для всех символов-элементов
Во Flash MX
Управление параметрами
Итак, вам нужно задать идентификатор (тот же самый идентификатор, что нужен для использования символа из ActionScript), поставить одну из двух галочек ( Export for runtime sharing, Import for runtime sharing ) и заполнить поле URL именем *.swf-файла, из которого будет производиться импорт символа.
Удобно настроить эти параметры для экпорта, в том числе URL, в библиотечном файле, а из него просто перетаскивать библиотечные символы в клиентские флэш-ролики. Тогда в последних останется правильно заполненным поле URL, а галочка Export for runtime sharing автоматически превратится в галочку Import for runtime sharing.
Во Flash MX больше нигде (кроме вышеописанного места) нельзя настроить что-то, относящееся
Из ActionScript тоже нет никакой возможности управлять настройками
Если совершенно необходимо держать под контролем то, что происходит при динамической загрузке повторно используемых компонентов, лучше отказаться от употребления loadMovie.
Обсудим детальнее, какие неприятности могут вас ожидать при использовании
BASE ) из следующей лекции).Для каждой флэш-платформы (имеется в виду OS + Browser) существует один "стандартный" способ задания библиотечного файла в поле URL. К счастью, для большинства платформ эти способы одинаковы и выглядят так: <имя файла>.swf. Есть и исключения, например, для Internet Explorer на MacOS это file:///<полный путь к *.swf-файлу>.
Если вы укажете URL к *.swf-файлу "нестандартным" для данной платформы способом, то при каждом использовании импортируемых символов флэш-плеер будет загружать их в память заново (по предположениям авторов, флэш-плеер сравнивает путь, прописанный в поле URL, c путем, возвращенным ему платформой, и загружает символ повторно, если пути не совпадают с точностью до символа)! Поэтому ничего не стоит написать флэш-ролик, который через 5 минут своей работы съест всю свободную оперативную память. С этим нужно быть очень аккуратным.
Вы спросите: "А как же написать флэш-ролик, работающий корректно в ситуациях с разными флэш-платформами" (в том смысле, что у них разные "стандартные" способы записи URL)? Авторам известен только один способ: нужно полностью динамически сгенерировать все содержимое тегов <OBJECT> и <EMBED> с помощью JavaScript, в котором выясняется тип браузера и, в зависимости от типа браузера, подставить нужное значение атрибута BASE тегам <OBJECT> и <EMBED> (см. также раздел "Изменение текущей директории" (атрибут BASE ) из следующей лекции).
А загружается из файла А.swf, а в клипе А лежит клип B, который загружается из файла B.swf и так далее. Во флэш-плеере до версии 6.0.65.0 была довольно условная поддержка этой функциональности, что выражалось в падениях флэш-плеера вместе с браузером (правда, Macromedia и не обещала, что это будет работать). Начиная с версии 6.0.65.0 во флэш-плеере официально добавлена поддержка "многозвенного" При использовании
В каждый *.swf-файл, из которого импортируются символы, нужно положить один дополнительный пустой символ и настроить ему такие же параметры
Это действие приводит к нужному результату: похоже, что в таком случае весь *.swf-файл загружается заранее, после чего все другие определенные в нем символы можно использовать без проблем.
Представьте себе такую ситуацию. Вы выкладываете свой готовый, протестированный проект на удаленный сервер и видите, что ничего не работает. По крайней мере, при первом открытии веб-страницы, потому что после нажатия Refresh все, скорее всего, загрузится нормально.
В чем же дело?
Видимо, произошла "рассинхронизация" разных клипов. Не забывайте, что каждый клип живет своей жизнью. Пока все файлы лежали в локальной сети, порядок выполнения кода был один, а после того, как файлы положили в Интернет, - он изменился.
Например, код в уже загруженных клипах "убежал" вперед и выполнился до выполнения кода еще не загруженных клипов, хотя планировалось все наоборот.
Чтобы решить эту проблему, нужно как-то отследить момент загрузки всех клипов, и только после этого начать выполнять нужный код. Как это сделать?
У runtime-shared модулей есть такое свойство: пока модуль (*.swf) полностью не загрузится, никакие клипы в нем играть не начнут. Этим можно воспользоваться.
Создадим в каждом из *.swf-модулей по пустому символу, в каждом из которых поместим приблизительно такой код:
if (_global.swfModulesCounter == undefined) _global.swfModulesCounter = 0; global.swfModulesCounter++;
Этот код увеличивает счетчик загруженных .swf-модулей на единицу.
Теперь можно поместить в отдельной сцене флэш-ролика все эти пустые символы, а в нужном месте (в котором и предстоит ожидать загрузки всех модулей) сделать трехкадровый цикл с проверкой значения счетчика. Если оно достигло общего числа нужных *.swf-модулей - значит, можно продолжать выполнение.
Выше мы рассмотрели возможности применения
Теперь приведем два примера, когда может быть полезно использовать оба механизма совместно.
Представьте себе такую ситуацию: вы используете только library, а в тот же каталог, в котором лежат все флэш-ролики.
Что делать?
Об этом нужно побеспокоиться заранее. Для всех компонентов, с которыми вы используете
Правда, по имеющейся у авторов неприятной статистике, что в сложных случаях данный механизм срабатывает лишь на 90%, в остальных случаях сами символы меняются, а параметры
Насколько известно авторам, во Флэш МХ не существует другого сколько-нибудь приемлемого
Рассмотрим теперь такую ситуацию. У нас есть несколько флэш-проектов, каждый из которых использует часть библиотечных компонентов, загружаемых с помощью
Но в одном проекте нам нужна одна часть библиотечных компонентов, а в другом - другая. Тем не менее, все флэш-ролики созданы на базе одного и того же
Кроме того, мы знаем, что если во Флэш МХ на сцену положен хоть один символ, который импортируется с помощью
Что же делать?
Вручную заходить в каждый флэш-ролик и удалять соответствующий
Есть лучшее решение: положить все
Это же решение можно (и нужно) применить к контролируемой загрузке клипов (см. выше в этой лекции): регулировать количество счетчиков в зависимости от действительно необходимого числа *.swf-модулей с помощью группирующего клипа.
Как мы видели, использовать механизмы sharing часто бывает удобно, однако это сопряжено и с рядом неприятностей. Если вам нужно всего лишь определить несколько функций (или классов) для общего пользования, то есть ничего кроме кода на ActionScript не нужно делать, проще воспользоваться инструкцией #include.
Если в рамках проекта создается много похожих флэш-роликов, то, даже если они используют общие компоненты, в каждом ролике отдельно придется сделать много сходных действий.
Чтобы избежать этого, можно использовать
Рассмотрим в качестве примера кое-какие вещи из тех, что могут лежать в
Первое, что вы, вероятно, захотите увидеть в
Скорее всего, вы применяете
Если во всех флэш-роликах вы пользуетесь какими-то общими функциями и классами, вполне можно сразу подключить эти #include -файлы в
Возможно, лучше подключение всех #include -файлов сгруппировать в клипе (опять-таки, author time shared ), чтобы всегда можно было добавить или удалить какой-то из них централизованно.
Вы помните, что для корректной работы runtime-shared компонентов необходимо сделать специальную процедуру (см. ранее в этой лекции).
Авторы предлагают выделить для этой цели в
Чтобы сделать сцену, откройте панель Scene ( Shift-F2 ) и нажмите на кнопку с изображением плюса. Сцены можно менять местами с помощью перетаскивания их мышью.
Авторы предлагают выделить в
Вероятно, что в процессе загрузки всех флэш-роликов можно будет выделить некоторые шаги, связанные с выполнением каких-то команд.
Например:
//скрытие всего _root'а (пока идет загрузка);
_root._visible = false;
// ожидание в трехкадровом цикле, пока не загрузятся всe
// .swf-модули (см. ранее в этой лекции);
if (_global.SWFModulesLoaded < _global.TOTAL_SWF) gotoAndPlay (2);
//применение нужных стилей ко всем контролам, которые теперь
// уже успели загрузиться;
_global.locTextStyleFormat.applyChanges(); //
_global.btnTextStyleFormat.applyChanges(); //
//посылка каких-то внутренних управляющих событий;
this.raise("InitializationComplete", "InitializationComplete",
EVT_TYPE_STRING);
this.raise("ModelInitializationComplete",
"ModelInitializationComplete", EVT_TYPE_STRING);
//обработка XML-скриптов;
if (_global.iniFileParams.xmlSetupString != undefined)
_global.ext.importFromXml(_global.iniFileParams.xmlSetupString);
_global.ext.sendRestoreStateEvent();
}
//открывание всего _root'а (все загружено);
_root._visible = true;
//остановка главного клипа
stop();
Все подобные действия нужно проделывать в
Иногда в сложных
Во Flash MX есть очень полезная вещь -
Зачем это нужно?
<OBJECT> и <EMBED> с необходимыми параметрами с помощью JavaScript (ранее в этой лекции упоминалось, для чего это может быть нужно). Напомним, что тег <OBJECT> (с соответствующим параметром CLSID ) служит для демонстрации флэш-ролика в Internet Explorer, а <EMBED> - (с соответствующим MIME-type) в браузерах, основанных на технологии Mozilla (собственно Mozilla, Netscape или Firefox).Во-первых, нужно создать HTML-файл, содержащий нужный вам код, параметризовав его специальными шаблонными переменными (см. далее).
Во-вторых, нужно положить этот файл в папку C:\Program Files\Macromedia\Flash MX\First Run\HTML (или аналогичную). Кстати, там же можно посмотреть примеры
И, в-третьих, нужно перезапустить Flash MX, после чего этот
Пусть вы редактируете $MO. Когда Флэш при $WI и $HE ) нужно вставить в тех местах, где указываются ширина и высота флэш-ролика.
Все шаблонные переменные начинаются со знака ' $ ' (если вам нужно будет вставить просто символ доллара, перед ним нужно будет поставить ' \ '), после которого следуют две большие латинские буквы, идентифицирующие переменную.
Ниже мы перечислим наиболее употребительные переменные
Самые нужные переменные
| Название шаблонной переменной | Код | Пояснение |
|---|---|---|
| Заголовок |
$TT |
Строчка, указанная после этой переменной будет показываться в комбо-боксе выбора |
| Начало описания |
$DS |
Описание |
| Конец описания |
$DF |
См. предыдущий комментарий. |
| Имя файла флэш-ролика | $MO |
Например, mymovie.swf. |
| Заголовок ролика | $TI |
Например, mymovie (то же, что $MO, но без расширения). |
| Ширина ролика | $WI |
В пикселах. |
| Высота ролика | $HE |
В пикселах. |
| Цвет фона | $BG |
Цвет, установленный в качестве дефолтового в вашем ролике (устанавливается в диалоге Modify / Document ). |
| Качество изображения | $QU |
Качество перевода векторной графики в изображения растровую в плеере (задается в закладке HTML диалога Publish Settings ). |
Параметры тега <EMBED> |
$PE |
Генерирует сразу несколько стандартных параметров тега <EMBED>: src (имя файла флэш-ролика), bgcolor (цвет фона) и quality (качество перевода векторной графики в растровую). |
Параметры тега <OBJECT> |
$PO |
Генерирует сразу несколько стандартных параметров тега <OBJECT>: movie (имя файла флэш-ролика), bgcolor (цвет фона) и quality (качество перевода векторной графики в растровую). |
Если вы собрались написать свою
Приведем соображения авторов по поводу устройства
Состав
loadMovie ).На любом уровне (будь то #include -файлы, *.fla-файлы или *.swf-файлы) очень полезно соблюдать модульность, то есть помещать все компоненты в отдельные файлы. Тогда вы всегда сможете без особых проблем сконфигурировать
Мы пока ни словом не обмолвились о том, где удобно хранить эти файлы (понятно, что это все имеет значение, только если вы пользуетесь механизмом
Из опыта авторов следует, что удобнее всего хранить эти библиотечные файлы на каком-нибудь подключаемом диске, например, М:. Допустим, у вас есть один библиотечный файл: library.fla. Тогда во всех флэш-роликах (то есть, в M:\library.fla. Это очень удобно тем, что вы в любой момент можете использовать нужную версию M:. Например, для разработчиков флэш-роликов этот диск может ссылаться на \\myserver\myshare\FlashMXLibrary, а для разработчиков библиотечных компонентов - ссылаться на C:\FlashMXLibrary\TheLatestTestVersion.
Теперь вспомните, в разделе, посвященном
Дело в том, что Flash MX ведет себя каким-то странно-интеллектуальным образом с путями, заданными в области source свойств символа (собственно, с настройками путей
M:M:M: (а не соответствующий этому сетевой или какой-нибудь еще путь).Представьте себе, что у вас есть большой проект с большим количеством не очень сложных флэш-роликов, которые должны быть достаточно "легкими", не требовать никаких дополнительных файлов для своей загрузки (весь флэш-ролик в одном *.swf-файле).
Но все-таки есть некоторые вещи, которые вы хотите менять одним махом во всех этих флэш-роликах, например, какие-то цвета, язык или что-нибудь еще.
Понятно, что в этом случае очень неудобно каждый раз вручную перекомпилировать все 50 флэш-роликов, особенно это чревато соблазном сохранять результаты прошлых компиляций, а это, в свою очередь, опасно тем, что некоторые последние изменения могут не попасть в сборку.
Именно для такого проекта "
Как же работает наш
ShellExecute() ;Ниже приведен откоментированный код этого
Фактически, наша программа просто делает вид, что пользователь открыл некоторый файл во Флэш МХ и выбрал из меню пункт File / Publish или пункт Control / Test Movie. Чтобы воспользоваться этим " compile или publish. Во втором случае будет произведена
#include "stdafx.h"
#define WINVER 0x0500
// чтобы можно было использовать функции Windows 2000
#include "windows.h"
#include "winuser.h"
#include "shellapi.h"
int main(int argc, char* argv[])
{
const int PUBLISH_MENU_ID = 40057;
// Номера получены из MSSPY
const int COMPILE_MENU_ID = 33371;
// с помощью этой утилиты были определены
const int CLOSE_CHILD_ID = 57602;
// идентификаторы интересующих нас пунктов меню
const int SAVE_ID = 57603;
if (argc != 3) {
// проверка на корректность исходных значений
puts ("First parameter: full .fla file name to compile,");
puts ("Second parameter: \"publish\" or \"compile\"");
return 0;
}
int MENU_ID = (!strcmp (argv[2], "publish")) ? PUBLISH_MENU_ID :
COMPILE_MENU_ID;
// в зависимости от пожеланий пользователя либо компилируем
// (ctrl-Enter), либо публикуем (ctrl-F12)
char buffer[200] = "Macromedia Flash MX - [";
char buffer1[200] = "Macromedia Flash MX - ";
// два варианта заголовка окна: иногда бывает так, а иногда иначе
char tmpbuf[200] = "";
char one[2] = " ";
for (int i = 0; i < strlen (argv[1]); i++) {
// формируем возможные названия окон
if (argv[1][i] == '\\') {
strcpy (tmpbuf, "");
continue;
}
else {
one[0] = argv[1][i];
strcat (tmpbuf, one);
}
}
strcat (buffer, tmpbuf);
strcat (buffer1, tmpbuf);
strcat (buffer, "]");
LPCSTR window_name = (LPCSTR) buffer;
//сформировали заголовки
LPCSTR window_name1 = (LPCSTR) buffer1;
WORD low = (WORD)MENU_ID,
// младший байт - идентификатор меню,
// старший должен быть равен 1.
high = 1; //accelerator
char param[400];
strcpy (param, "\"");
strcat (param, argv[1]);
strcat (param, "\"");
printf ("%s\n", param);
puts ("Trying to open file");
//открываем нужный *.fla-файл
ShellExecute (0, "open", param, NULL, NULL, SW_SHOW);
HWND h = 0, h1 = 0;
puts ("Trying to find the main window");
do {
Sleep (100);
h = FindWindow ("SmartSketchMDIFrame", window_name);
//ищем окно
h1 = FindWindow ("SmartSketchMDIFrame", window_name1);
} while (!h !h1);
if (!h) h = h1; //нашли одно или другое окно
puts ("Sending commands");
// посылаем сообщение о компиляции или публикации
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
//сейчас мы закроем все ненужные окна
low = (WORD)CLOSE_CHILD_ID;
puts ("Closing child windows");
if (MENU_ID == COMPILE_MENU_ID)
// если была компиляция, то закрываем это окно
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
low = (WORD)SAVE_ID;
// сохраняем файл
SendMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
// полностью закрываем сhild-окно.
// SendMessage работает синхронно, а PostMessage -
// асинхронно. Здесь можно использовать PostMessage(), потому
// для продолжения работы ничего дожидаться не нужно.
low = (WORD)CLOSE_CHILD_ID;
PostMessage (h, WM_COMMAND, MAKEWPARAM (low, high), NULL);
//пробуем отыскать диалоговое окно
HWND hMain = 0, hDialog = 0;
puts ("Searching for the dialog boxes");
do {
// ищем диалог о сохранении файла, который, возможно,
// появился как результат выполнения команды закрытия окна.
hMain = FindWindow ("SmartSketchMDIFrame", "Macromedia Flash MX");
if (hMain) {
puts ("There were no dialog");
break;
}
hDialog = FindWindow (NULL, "Flash MX");
if (hDialog) {
high = BN_CLICKED;
low = IDNO;
SendMessage (hDialog, WM_COMMAND, MAKEWPARAM(low, high), NULL);
//закрываем диалог
break;
}
Sleep (100);
} while (true);
printf ("Main = %Xh, Dialog = %Xh\n", h, hDialog);
return 0;
}
subst - исключительно полезная утилита для создания виртуальных дисков, которые, как уже упоминалось, очень удобно использовать в качестве места размещения файлов-источников для subst является функция Map Network Drive, доступная из Windows Explorer.
Синтаксис:
subst <drive>: <directory> для создания виртуального диска;subst <drive>: /d для удаления виртуального диска. При выполнении этой команды убедитесь, что текущая директория не лежит на виртуальном диске.Жесткие ссылки ( library. Вы можете организовать автоматическое обновление символов в library или файлы, лежащие в нем. Вот для этого как раз и служат жесткие ссылки: эти файлы можно залинковать на сетевой диск, и они будут обновляться автоматически.
Есть программы, которые позволяют это делать, например, Far 1.5 ( Alt-F6 ). Обязательное условие: все ссылки должны лежать в одном томе NTFS, то есть дизайнеры флэш-роликов не могут держать свои каталоги для разработки на локальных дисках.
Обычно
Разработка флэш-проектов здесь абсолютно не является исключением. Поэтому рассмотрим некоторые аспекты этой проблемы более подробно.
Существуют разные
Подробно рассматривать достоинства и недостатки каждой из них мы не станем, а примеры, приводимые ниже, будут касаться MS VSS, потому что именно ею мы пользовались для управления одним из флэш-проектов.
Выбор был сделан вполне тривиально: MS Visual SourceSafe - это наиболее простая система. Правда, позже мы обнаружили, что MS VSS очень хорошо подходит для флэш-проектов. Например, в ней по умолчанию запрещены multiple checkouts (которые не имеют смысла при работе с двоичными файлами *.fla), а также есть очень удобные инструменты links и shadow folders, о которых мы расскажем далее.
Что для флэш-проектов является характерным - так это то, что исходные файлы имеют двоичный формат, что отнюдь не способствует совместной работе над ними и последующему слиянию ( merge ) файлов. Что ж, тем жестче нужно ограничивать одновременные изменения .fla-файлов (и запрещать unreserved, или multiple, check-outs ).
MS VSS по умолчанию и работает в таком режиме.
Разумно также (как уже неоднократно замечалось ранее) выносить максимум кода за рамки *.fla-файлов (в include -файлы). Тогда можно настроить возможность одновременной работы над этими файлами.
При интеграции очень удобно пользоваться такими механизмами (или их аналогиями), как ссылки ( links ) и теневые папки ( shadow folders ), которые есть в VSS.
Ссылки VSS - это аналог жестких ссылок (
Приведем пример. Предположим, вы изменили файл core.fla и выполнили check-in (внесли изменения). Поскольку на core.fla существуют ссылки в проектах $/core/ и $/author-shared, он изменился сразу в двух проектах. У проекта $/core/ настроен shadow folder в \\myshare\myProject\src (здесь под \\myshare имеется в виду абстрактный сетевой путь, являющийся корнем для флэш-проектов), а у проекта $/author-shared - в \\myshare\\myProject\author-shared, в результате чего файл изменился сразу в двух каталогах: в архивном каталоге проекта ( src ) и каталоге, который подключен в качестве сетевого диска (например, как M:) и из которого обновляются все флэш-ролики при компиляции ( author-shared ).
Точно так же с помощью links и shadow folders можно обновлять *.swf-файлы, причем если вы еще используете жесткие ссылки в файловой системе, то *.swf-файлы могут автоматически обновиться в рабочих директориях дизайнеров.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.