Диплом
Совсем забыл похвастаться. Этим летом закончил ВМиК МГУ им. Ломоносова
Под катом - фото диплома. Обратите внимание на выделенные оценки ![]()

Некоторые особенности сборки Ant-ом Flex + AIR проекта на Windows & Linux
Опишу несколько моментов в сборке, которые могут быть вам интересны, если выполнено одно из условий:
- Собираете проект вне Flex Builder
- Проект собирается в двух версиях параллельно - Flex и AIR
- Один и тот же Ant билд-файл должен работать на Windows и Linux - например, чтобы автоматизировать сборку с помощью Bamboo, работающего обычно на Linux веб-сервере
Не претендую на best-practice.
Используйте .jar или скрипт версии приложений для сборки (mxmlc.jar, compc.jar)
Очевидно, что на Linux .exe и .bat не пойдут.
Есть еще вариант использовать скрипты, например mxmlc, однако мне кажется, что там могут быть проблемы с передачей параметров (не проверял). Мне кажется, надежней вызывать сразу компилятор без посредников, чтобы не иметь лишних источников багов.
На Linux mxmlc.jar почему-то не может найти flex-config.xml, если папка процесса не является ${flex.home}/frameworks (на Windows такой проблемы нет) - поэтому приходится везде указывать абсолютные пути:
- <java jar="${FLEX_HOME}/lib/mxmlc.jar" dir="${FLEX_HOME}/frameworks"
- fork="true" failonerror="${fail.on.module.error}" maxmemory="500m">
- <arg value="${basedir}/${module.name}.mxml"/>
- <arg value="-output=${module.output.dir}/${module.name}.swf"/>
- </java>
Подозреваю, что это можно пофиксить хитрым параметром +flexlib="$FLEX_HOME/frameworks” (см. bin/mxmlc)
Сборка AIR .swf
Можно вызвать скрипт amxmlc, а можно запустить тот же mxmlc.jar, но с параметром +configname=air. Однако учтите - этот параметр всегда должен идти первым, иначе компилятор не поймет.
Отсутствием этого параметра может быть вызвана ошибка:
Error: Unable to locate specified base class 'mx.core.Application'
Error: only one source is allowed in the filespec
Эту ошибку можно словить, если написать следующее:
- <condition property="additional.args" value="+configname=air" else="">
- <isset property="is.air"/>
- </condition>
- <java jar="${FLEX_HOME}/lib/mxmlc.jar" dir="${FLEX_HOME}/frameworks"
- fork="true" failonerror="true" maxmemory="500m">
- <arg value="${additional.args}"/>
- <arg value="${basedir}/${source.current}/${root.file}"/>
- <arg value="-output=${main.output.file}"/>
- </java>
Т.е. для Flex версии первый параметр будет пустой. Просто задайте в случае, если ${is.air} не задано что-нибудь очевидное, вроде else="-as3=true".
Error: unable to resolve ‘embed-image.png’ for transcoding
Эта ошибка может появиться на Linux-машине, в то время как на Windows все отлично собирается. Дело в том, что Windows не обращает внимания на case, поэтому вам придется синхронизировать написание имени файла в Embed-директиве и в файловой системе:
Embed-Image.PNG -> embed-image.png
SVN не поддерживает переименование файлов с отличием лишь в case-е. Поэтому придется сначала закоммитить удаление файла с неправильным именем, а потом закоммитить исправленный.
Пробелы на конце строк в properties-файлах
Будте внимательны и не ставьте пробелы на конце строк в properties-файлах. Если этот property станет именем файла, то у вас возникнет куча проблем, например файл нельзя будет удалить с помощью FileZilla с удаленной машины - сервер скажет вам 550 file not found - все из-за разной работы с пробелами на концах файлов.
Черный баг или большое разочарование
Этот пост будет о самом грустном, а именно о багах компилятора mxmlc, которые мало поддаются логическому осмыслению и локализации - и поэтому отнимают особенно много времени и сил. Постараюсь описать их, в надежде что когда-нибудь это поможет и Вам, начну с более понятных багов.
-incremental=true
При использовании инкрементной компиляции, mxmlc создает project_123456.cache файлы, в которых хранит скомпилированный но не “прилинкованный” код - так он уменьшает время повторной компиляции, перекомпилируя только измененные и импортирующие измененные файлы
Существуют неизвестные проблемы, по которым в результате использования этой возможности в результате может собраться полная чушь. Для дебага это не страшно - всегда можно удалить .cache и пересобрать, но не советовал бы использовать инкрементную компиляцию при сборке публичных версий проекта.
CSS-файлы со стилями, находящиеся не в корне одной из папок из -source-path.
Описание в Adobe JIRA. Если .css-файл
.text { borderSkin: ClassReference("com.adobe.skins.MyRectangularBorder ");который Вы пытаетесь скомпилировать в .swf, лежит в папке src/assets/, а не в src/, то при компиляции Flex Builder-ом Вы будете иногда получать ошибки вида
1120: Access of undefined property MyRectangularBorder" and "1172: Definition com.adobe.skins:MyRectangularBordercould not be found.
При компиляции же из командной строки Вы будете получать их всегда. Еще иногда вам могут сказать, что у .css-файла указан неправильный package (sic!) - хотя у .css файлов package-а не бывает принципиально.
Workaround - класть все компилируемые .css в корень папок из -source-path.
Gaurav Jain из команды Adobe считает, что это не баг. На данный момент issue закрыт, нельзя ни проголосовать, ни оставить комментарий.
CSS-файл может быть не найден, если он находится в разных source-path с использующим его MXML-кодом.
Описание в Adobe JIRA. Снова наш друг Gaurav Jain. Как он ни старался убедить всех, что “I don’t think its a bug", пофиксить все-таки пришлось.
Использование “/” в начале Embed(source="/…") не работает при компиляции из командной строки.
Описание в Adobe JIRA. Тут уже дело в том, что Flex Builder и mxmlc имеют разные механизмы разрешения путей. Jono, я в Вас верю, добейте этот баг.
Ошибка в одной из Embed-директив может заставить компилятор показать ошибочными все Embed-директивы.
Описание этого бага в блоге. В комментах упоминают, что это может быть вызвано даже не ошибкой в одном из Embed-ов, и вот мы подходим к самому плохому.
Ошибка в компиляции любого файла (ваша или компилятора) крайне редко может быть отображена компилятором как ошибка в никак не отсносящемуся к ошибочному коде.
Сразу скажу, перед каждой попыткой сборки я делал полное удаление .cache и всего, что было собрано в прошлый раз.
I believe что такие баги есть и что именно этот, самый черный вид ошибки компилятора, я и испытывал на себе весь сегодняшний день. Было несколько ситуаций, когда я менял ревизию одного файла LeftTreeNav и на 663 ревизии все отлично работало, а на 664 мне выдавалось 3 ошибки в файле ContactsWindow и 20 ошибок неверных Embed-директив. Разница между ревизиями была в добавлении нескольких безобидных строк кода, не имеющих никакого отношения к показанным ошибкам.
Далее - еще интересней. Путем переформатирования файла ContactsWindow я добился исчезновения этой ошибки при компиляции с указанием
-define+=CONFIG::deployMode,'\'debug\''
Однако, при указании
-define+=CONFIG::deployMode,'\'test\''
она появлялась снова (все остальные параметры компиляции оставались те же). Не могу передать всех эмоций…
В итоге, все спасло замена большого switch-блока в ContactsWindow на if-else-if-else-if-… Несколько постов назад я писал про хитрые баги в компиляции сложных условных конструкций, и видимо сейчас проблема была как раз тут. Не получив рабочего результата в классе ContactsWindow, компилятор уходил в пике и не возвращался, попутно сыпя несуществующими ошибками из остальных классов.
Надеюсь, Вы никога не столкнетесь с подобными вещами
А если столкнетесь - то обязательно напишите, что это было и как починилось. Удачной сборки!
Russian Flash Awards и 7-ая RAFPUG
Чтобы никто не говорил, что забыл: сегодня в 19:00 в клубе «Меццо Форте» (Москва, 1-я Останкинская ул., д. 53, метро “ВДНХ") будет проходить Russian Flash Awards и 7-ая RAFPUG.

Дополнительная информация в Google-группе и у Роста.
6-ая RAFPUG
Автор фотографий - Алексей «Vooparker» Аникутин
На 6-ой встрече нашей RAFPUG Constantiner предложил сделать 30-минутный доклад о проблемах и решениях flash-клиента на портале top4top.ru. Я предложил своим коллегам Филиппу «FSB» Бондареву и Игорю «peace» Андрееву сделать наш доклад вместе (по сути переложил на них всю работу
), и так уж получилось что они вместо 25 минут рассказывали 2 часа.
Начал наш архитектор, Игорь. Одна из первых фраз была типа «то ли руки не оттуда ростут, то ли условия были таковы», на что Артемий предложил не впадать в уныние
Сотрудники Flexis соорудили доступ в интернет, и Игорь перешел от слайдов к показу живого сайта через Internet Explorer.
То ли за полгода мы так и не соорудили нормальное определение версий, то-ли и правда в IE был старый плеер, но все увидели предложение обновить плеер вместо top4top
Фидбек от Flexis? Какой там плеер в IE был? В Опере все сразу заработало. Следующие 20-30 минут Игорь ходил по top4top.ru в браузере и оказалось, что функционала-то немало.

Затем он перешел к более системным вещам и решениям, скоро тут появиться его презентация.
Настала очередь Филиппа. Он рассказывал про User Account, показывал запретные картинки, создавал и уничтожал планеты во вселенной.

Особенно запомнился момент, когда Филипп стал убирать красные глаза с помощью инструмента редактирования фото в User Account’е «Человеку-Жопе», символу IT-отдела портала:

Презентация Филиппа:
После короткого перерыва я за 5 минут протараторил свою презентацию:
Выводы (Филипп и Игорь со мной не согласны, их выводы я надеюсь тоже добавить в пост):
- Использование двух кривых версий (flash и html) одного контента - это победа технологий над здравым смыслом.
- На данный момент мне ясно, что лучшим является html решение с вставками flash там, где это абсолютно необходимо и с возможностью получить хоть что-то если FP недостаточно высокой версии
- Требование установить последний релиз плеера отпугнет от Вас бОльшую часть аудитории (если она состоит не из флешеров)
- Если не страшен предыдущий пункт и решено сделать портал на FP, то необходимо использовать Flex Framework
И, наконец, главный вывод:
- Необходимо предоставлять сервис максимального качества при текущей конфигурации машины пользователя, без необходимости установки обновлений чего-либо. Если он захочет (и у него есть такая возможность), то установит все, что попросите.

Я.
В целом получилось позитивно и, надеюсь, не очень занудно. Спасибо вам за вопросы и за то, что пришли.

Отвечаем на разные вопросы.
Настала очередь Артемия. Его доклад о нововведениях во Flash Player 10 Beta состоял из демонстрации множества примеров и активных обсуждений в зале. Мне больше всего понравилась генерация звука - вспомнился MS DOS, и сохранение файлов без участия сервера. Большое спасибо ему за доклад!

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








Профилирование ActionScript 3.0 проекта
Если Вы не раз профилировали проект, то что-то интересное, возможно, найдете ближе к концу поста.
Вступление
На данный момент единственный инструмент для профилирования это Flex Builder Profiler (хотя необходимый профайлеру API открыт - делай кто хочешь).
В процессе разработки top4top.ru не раз возникали проблемы с утечками памяти, иногда для их устранения приходилось даже вызывать разработчиков в офис по ночам. Иногда память не освобождалась вообще - росла с шагом 50-200 mb от числа переходов по страницам:

Это очень заметно и чинятся, как правило, за несколько часов. Сложнее сказать, есть ли утечка памяти, и где она по такому графику:

Тут уже мало что понятно. Поэтому первый вопрос - как определить, есть ли в приложении утечка памяти.
Определение факта утечки памяти - общие моменты
Тут нам очень поможет функция взятия разности между двумя dump-ами памяти приложения:

Результат - таблица Loitering Objects View, цитата из хелпа:
The Loitering Objects view shows you the differences between two memory snapshots of the application that you are profiling. The differences that this view shows are the number of instances of objects in memory and the amount of memory that those objects use. This is useful in identifying memory leaks. The time between two memory snapshots is known as the snapshot interval.
Для нас в ней самое интересное это имена классов и количество их оставшихся экземпляров.

На схеме выше приведен первый приходящий в голову вариант по поиску memory-leak-ов на Главной Странице. Однако он не работает - в список “бездомных” объектов попадают не только лики с Главной страницы, но и все объекты, создаваемые в Профайле 1.
Определение факта утечки памяти - стратегии
Можно придумать много разных стратегий. На картинке ниже прямоугольниками обозначены состояния системы, в которых инстанциируются объекты. При уходе из состояния его объекты должны удаляться. У нас в top4top состояния были страницами сайта, иногда - разделами (главная, чат).

Устранение утечки
- В простых случаях достаточно просмотреть код остающихся в памяти классов для устранения ошибки
Если она не очевидна, то тут нам поможет окошко Object References, которое показывает все ссылки на объект и открывается по дабл-клику на элементе в таблице Loitering Objects:

Сложнее всего искать утечки, из-за которых не удаляется вообще ничего. В этом случае два предыдущих способа не работают.
Именно такая ситуация у нас и была. Утечка находилась в часто исползуемом визуальном компоненте (назывался HtmlText). При создании компонента-страницы LayoutIndex в него где-то глубоко добавлялся экземпляр HtmlText и с тех пор вся иерархия (даже после удаления компонента всей страницы из дисплей-листа) становилась неуязвима для Garbage Collector’а.

Способ борьбы тут оказался довольно простой:
- package
- {
- import flash.display.Sprite;
- import flash.events.Event;
- public class test extends Sprite
- {
- private var picture:Picture;
- private var mainText:HtmlText;
- private var enterButton:SomeButton;
- private var closeButton:AnotherButton;
- public function test()
- {
- initContent();
- }
- private function initContent():void
- {
- picture = new Picture();
- addChild(picture)
- // Дальше в том же духе инициализируем и
- // добавляем другие компоненты
- // И подписываемся на удаление со сцены
- addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
- }
- // Удаляем все ссылки на дочерние элементы
- private function onRemovedFromStage(event:Event):void
- {
- picture = null;
- mainText = null;
- enterButton = null;
- closeButton = null;
- while (numChildren > 0)
- removeChildAt(0);
- }
- }
- }
Таким образом в памяти остаются только “текущие” объекты и мы с легкостью с помощью таблицы Loitering Objects их удаляем.
Делать подобные удаления всегда или добавлять этот код только в процессе устранения ликов - это отдельное решение.
Также у нас действует стандарт, что все подписки на события должны быть объявлены с Weak Reference, если нет четких противопоказаний. За весь проект случаев, когда нужна была подписка с жесткой ссылкой было всего несколько. false, 0, true!
Напоследок - регулярное выражение для поиска не-weak подписок: addEventListener\(([\w.\"]*), (\w*)\) (автор: Алексей «Vooparker» Аникутин).
top4top - процесс разработки
Периодически фотографирую интересные моменты нашей работы над порталом top4top.ru, вот два из них:
Алексей «Vooparker» Аникутин, один из авторов yarovoy.com фиксит проблемы upload-а файлов на Mac (если сервер использует переадресацию после окончания загрузки, то на Mac это не работает):

Олег, JAVA-программист, пришел на работу прямо с прибывшего утром проезда:

Диаграммы классов ActionScript 3.0 и Flex - постеры.
Многие в курсе, но тем не менее: в далеком 2006-ом появились диаграммы классов по ActionScript 3.0 и Flex 2 в виде PDF документов, с которых можно напечатать постеры. Фрагмент Flex-диаграммы взят из поста “Ted On Flex”:

ActionScript 3.0 Class Diagram на Flex.org
Flex 2 Diagram на Flex.org
VooDoo подсказывает: Вышеперечисленные + еще куча постеров (Flex 3, AIR)
Напечатали ActionScript 3.0 диаграмму на цветном принтере на А3 с максимальным качеством, получилось мелко, видно только вплотную. Так что если есть возможность, лучше печатать на А2 или А1. На А3 со стандартным качеством вообще ничего не разобрать.
Баги в средствах разработки Flash Platform
Баги есть везде (для справки: шрединбаг, мандельбаг, борбаг), в том числе в mxmlc и Adobe Flex Builder 3. Попробую перечислить опасные и поедающие время баги - а это обычно те, которые абсолютно нелогичны (Ваши варианты в комментах).
- Ранний return в функции: если в начале функции поставить return, то в некоторых случаях это ведет к обрушению компилятора.
Memory-leak при использовании локальной переменной в конструкторе класса - она становится членом класса (гейзенбаг, сейчас повторить не удалось. Источник - Игорь “peace").
- public function ClassConstructor()
- {
- // Иногда при подобном объявлении у экземпляров
- // класса будет появляться поле clip и данный объект
- // не будет собран Garbage Collector'ом.
- var clip:MovieClip = new MovieClip();
