Monthly Archive for August, 2009

Augmented reality…

уже на iPhone.

Dependency Injection

Dependency Injection и принцип Inverse of Control в программировании используются уже давно. Я как понял DI — это термин, который Мартином Фаулером используется для обозначения того же IoC. Что же это такое и как его использовать нам, простым флэш разработчикам.

Все просто. Основная идея — при создании объекта ему даются (инжектируются) уже готовенькие объекты, в которых он нуждается (зависимости). Каждый из нас, интуитивно полагая, что это гуд, использовал Dependency Injection в той или иной мере. Вот простой код.

public class One{
    public function One( two: ITwo )
    {
        this.two = two;
    }
}

public class Two implements ITwo {
    ...
}

new One( new Two() );

Как видно, объекту класса One мы передаем объект с интерфейсом ITwo при создании. Перед нами простой пример так называемого Constructor Injection. Также есть Property Injection, когда класс предоставляет public свойство или сеттер, через который ожидает получить некоторый объект, в котором нуждается. Идея проста до безобразия и позволяет проще переиспользовать классы, которые друг на друга не завязаны.

Противоположный подход — создавать все dependency внутри класса, при этом классы становятся привязанными друг к другу, что усложняет внесение изменений.

Интереснее же все становится, когда на сцену выходит IoC Contaner. Под контейнером понимается некоторое пространство для объектов, который по определенным правилам эти объекты сам конфигурирует и сам подставляет dependencies куда и кому нужно. Проще говоря, некоторый фреймворк, который сам соображает (с нашими подсказками) как собрать те или иные объекты и какие зависимости им нужны.

AS3.

Речь пойдет о чисто AS3 проектах. Они обычно небольшие в отличие от Flex проектов, которые можно сравнить с Java Enterprise проектами. Если в Java существует толпа IoC фреймворков (как я понимаю самый популярный Spring Framework), то для ActionScript до недавнего времени все было как-то грустно. Конечно, AS3 язык гораздо моложе, чем Java, скажете вы.

Между тем я случайно наткнулся на Syringe, который мимикрирует со Spring, повторяя метод конфигурации через XML, но последняя версия выпущена в бородатом 2006м. Видим, что какие-то попытки перенести функциональность Spring на ActionScript3 велись, но не были поддержаны сообществом, потому что сообщество не было к этому готово. И, конечно же, потому, что большинство AS3 проектов небольшие, на одного программиста и дизайнера.

Какое-то время уже существует официальный Spring ActionScript (бывший Prana). Этот фреймворк вроде бы развивается и сейчас остановился на версии 0.8.

Favour of the month безусловно является Parsley, версия 2 которого радикально изменилась и поддерживает множество вкусных фишек. В том числе и для pure AS3 проектов.

Применение.

Как-то давно на основе Parsley 1.* я набросал себе небольшой фреймворк, который использую при создании и конфигурировании видео плееров и фото галерей.

Значит, допустим у нас есть видео плеер с архитектурой MVC. Разные проекты предусматривают разное расположение визуальных элементов и разные функции. Чтобы каждый раз не копипастить все это, делаем максимально decoupled компоненты и собираем их IoC контейнером при помощи XML конфига.

Вот пример такого конфига для одного из плееров. Видим команды контейнеру по сборке объектов. Любую можно убрать или добавить и плеер пересоберется подругому. Порой, даже не нужно перекомпилировать проект. Конечно, данный пример не использует таких мощных фишек контейнера, как инжектирование по типу, просто мой старенький этого не умеет.

<?xml version="1.0" encoding="UTF-8"?>
<container>
<commands>
<!-- Скин плеера -->
<object name="skin" class="com.qq.videoplayer.skin.PPSkin" />
<!-- Сам плеер -->
<object name="player" class="ru.valyard.media.mediaplayer.VideoPlayer">
<constructor-args>
<object ref="skin" />
</constructor-args>
<!-- Контейнер для контролов -->
<view name="controls" class="ru.valyard.upa.mvc.views.FixedContainer" />
<!-- Компонент показывающий картинку до проигрывания -->
<view name="preview" class="ru.valyard.media.mediaplayer.views.controls.PreviewView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Анимашка, которая моргает во время буферизации -->
<view name="buffering" class="ru.valyard.media.mediaplayer.views.controls.BufferingView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Большая кнопка Play в центре -->
<view name="bigPlay" class="ru.valyard.media.mediaplayer.views.controls.BigPlayButton" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Экран как видео проигралось -->
<view name="stopView" class="ru.valyard.media.mediaplayer.views.controls.StopView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Верхние контролы -->
<view name="dynamicpanel2" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">10</property>
<property name="xRule">5</property>
<property name="inactiveYRule">-70</property>

</view>
<view name="top" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel2">
<constructor-args>
<int>0</int>
</constructor-args>
</view>
<!-- Fullscreen -->
<view name="fullscreen" class="ru.valyard.media.mediaplayer.views.controls.FullscreenButtonView" parent="top"/>
<!-- Share -->
<view name="shareButton" class="ru.valyard.media.mediaplayer.views.controls.ShareButtonView" parent="top"/>
<view name="popout" class="ru.valyard.media.mediaplayer.views.controls.PopoutView" parent="top"/>
<!-- Основные контролы -->
<view name="dynamicpanel" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">H-42</property>
<property name="inactiveYRule">H</property>
</view>
<view name="panel" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel">
<constructor-args>
<int>2</int>
</constructor-args>
</view>
<!-- Watermark -->
<view name="watermark" class="ru.valyard.media.mediaplayer.views.controls.SymbolView" parent="dynamicpanel">
<constructor-args>
<string>Watermark</string>
</constructor-args>
<property name="xRule">W</property>
</view>
<!-- Play/pause buttons -->
<view name="playpause" class="ru.valyard.media.mediaplayer.views.controls.PlayPauseView" parent="panel"/>
<view name="prev" class="ru.valyard.media.mediaplayer.views.controls.PreviousView" parent="panel"/>
<view name="next" class="ru.valyard.media.mediaplayer.views.controls.NextView" parent="panel"/>
<view name="line" class="ru.valyard.media.mediaplayer.views.controls.LineView" parent="panel">
<property name="widthRule">W-playpause.width-sound.width-next.width-prev.width</property>
<property name="leftSpace">1</property>
<property name="topSpace">12</property>
<property name="rightSpace">4</property>
<property name="scrollerDist">6</property>
</view>
<!-- Sound on/off button -->
<view name="sound" class="ru.valyard.media.mediaplayer.views.controls.HorizontalSoundView" parent="panel"/>
<!-- Share window -->
<array name="sizesArray">
<string>640x480</string>
<string>480x360</string>
<string>320x240</string>
</array>
<view name="shareView" class="ru.valyard.media.mediaplayer.views.controls.ShareView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
<property name="sizes" ref="sizesArray"/>
</view>
<!-- Ad -->
<view name="ad" class="ru.valyard.media.mediaplayer.views.thirdparty.TremorMediaAdsView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
<property name="id">123</property>
</view>

<module class="com.qq.videoplayer.modules.PlayCount" name="playcount">
<constructor-args>
<string>http://qq.com/qq.php</string>
</constructor-args>
</module>

<!-- Debug actions -->
<action class="ru.valyard.media.mediaplayer.actions.TestAction" name="*" priority="3" />

<!-- XML loader class -->
<object name="loader" class="ru.valyard.media.mediaplayer.loaders.PlaylistXMLLoader" />
<method name="registerLoader">
<object ref="loader" />
</method>

<!-- Embed HTML template -->
<property name="embedHTMLTemplate">
<![CDATA[<object width="%W%" height="%H%"><param name="movie" value="http://www.qq.com/swfs/embed.swf?id=%ID%"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.qq.com/swfs/embed.swf?id=%ID%" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="%W%" height="%H%"></embed></object>]]>
</property>
<!-- -->
<property name="pageURLTemplate">
<![CDATA[http://www.qq.com/video/%PAGE%]]>
</property>
<!-- -->
<property name="dataURLTemplate">
<![CDATA[http://www.qq.com/xml/%DATA%]]>
</property>

<property name="mediaURLTemplate">
<![CDATA[http://www.qq.com/videos_final/%URL%]]>
</property>
</object>
</commands>
</container>

С первого взгляда все сложно, хотя такая конфигурация успела сохранить мне кучу времени при создании однотипных модульных видео плееров немного отличающихся по скину и функциональности.

Плюсы.

Про конфигурирование плеера я уже сказал. Это несомненно плюс. Этот подход позволяет максимально разделить используемые объекты друг от друга и легко переиспользовать их в других проектах. В осноном, избавляет от неободимости писать кучу конфигурационного кода. Конечно, приведенный здесь конфиг не является идеальным примером. СтОит почитать хелп Parsley, который имеет куда более продвинутые способы конфигурирования.

Минусы.

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

Детская болезнь — велосипеды изобретать

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

Что касается флэша, в мои юные годы сам флэш был молод, но уже где-то на шестерке помню программы представляли собой какое-то сборище кода на ключевых кадрах. Потом пришло осознание того, что надо бы как-то структурировать как минимум места с кодом. Тем временем флэш рос и развивался, я стал заводить что-то типа библиотек объектов и следовать некоторым логичным паттернам программирования. AS2 и AS3 вывел флэш программирование на новый уровень. Среднестатистический AS3 разработчик высунул голову в мир “старших” братьев-языков и спросил “Ну что тут у нас?”. На что получил уйму непонятных слов, типа паттерн, фреймворк, рефакторинг и всяческий юниттест.

В основном, конечно, стоит винить кривую развития AS, и то, что серьезным языком он стал совсем недавно.

В итоге имеем Флексеров, которые скорее всего пришли из Java, “покадровых разработчиков”, которые до сих пор не хотят учить AS3, и кто-то между ними.

Говоря о чекпоинтах, каждый программист рано или поздно понимает вроде бы очевидные на наш взгляд вещи. Из своего опыта он приходит к тому, что уже n-цать лет все знают и написали кучу книжек и библиотек. Но говоря об AS3 программистах, всякие интересные фреймворки стали появляться не так давно и преимущественно под Flex. А что делать тем, кто вынужден разрабатывать сложные вещи не используя Flex Framework…

Тут мы начинаем изобретать велосипеды. Часто вместо того, чтобы оглянуться вокруг и разобраться что же все-таки есть из того, что можно уже не изобретать. Почти все пользуются простыми опенсорс библиотеками, типа Tweener или TweenLite, делают простое 3D с помощью Papervision3d или Away3d. А вот с глобальными шаблонными фреймворками как-то более грустно. В основном у каждого по своему подходу и следовательно по своему велосипеду.

Хорошо еще, когда велосипед свою работу с горем пополам выполняет. Я видел такие чудеса, которые копипастились из проекта в проект и были больше похожи на какие-то проволочные велосипеды с бетонными колесами. Кто-то использует, например, PureMVC и старается придерживаться некоторых паттернов — это следующий чекпоинт. Но, даже например в PureMVC мне много чего не нравится и кажется ограничивающим, хотя фреймворк-то микроскопический.

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

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

Вот и сейчас. Я, можно сказать, загорелся некоторыми интересными принципами и реализациями.

Когда уже это пройдет и я займусь настоящим делом, которое приносит доход, а?

Вечный поиск идеального инструмента

Я, как программист и немного дизайнер, держу на рабочем месте тетрадку А4 в клеточку, на которой набрасываю и пытаюсь структурировать свои идеи. Основная проблема — часто приходится вырывать листки, чтобы держать на виду сразу два-три, а потом они волшебным образом теряются или оказываются залитыми пивом и заляпанными жирными пальцами. Также, хорошие идеи приходят не сразу, и листочки превращаются в перечеркнутое месево. Плюс, я не люблю писать карандашом.

В последнее время использую тетрадку и маленький блокнотик, на котором расписываю и выкидываю мусор из идеи прежде чем аккуратненько поместить в тетрадку. Позволяет получать листки с бОльшей площадью полезного материала и реже их выдирать.

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

Теория заговора и mxmlc

Claus Wahlers пишет, что во время работы над своим проектом по разкомпиляции swf на as3, он наткнулся на некоторый недокументированный тэг ProductInfo, который mxmlc по умолчанию вкомпиливает в swf. Смотрим, что в него пишется:

  • ProductID (UI32)
    0: Unknown
    1: Macromedia Flex for J2EE
    2: Macromedia Flex for .NET
    3: Adobe Flex
  • Edition (UI32)
    0: Developer Edition
    1: Full Commercial Edition
    2: Non Commercial Edition
    3: Educational Edition
    4: Not For Resale (NFR) Edition
    5: Trial Edition
    6: None
  • Major Version (UI8)
  • Minor Version (UI8)
  • Build Low (UI32)
  • Build High (UI32)
  • CompilationDate (UI64)
    Milliseconds since 1.1.1970

Замечаем поле Edition и вспоминаем теорию заговора. Что если меня заметят в выпуске промо сайтов на Non Commercial Edition? Что если я скажу, что работаю на купленной полной версии, когда swf говорит, что скомпилено-то триалом? Не нравится мне наличие этой информации в свободном доступе в моих файлах.

Кто займется созданием утилиты для удаления этого тэга?

Визуализация наследования

Joa Ebert у себя в блоге запостил забавную штукупрограммка для экспорта цепочки наследования из скомпиленного SWF + визуализация этого барахла через Graphviz.

Опробовал на одном из своих плееров. С удивлением узнал, что импортнутые из SWC мувики имеют тип FlexSprite и тянут за собой немного флексового барахла.

Graphviz, конечно, полное убожество. Нельзя даже двигать ноды, чтобы удобненько распечатать.

Кстати, если на маке у кого не обновилась JVM до 1.6, то тут написано как это сделать.

Process terminated without establishing connection to debugger

Надо было поправить свою старую AIR аппликуху, отрыл исходник, скачал AIR SDK, запускаю Flex Builder’ом и получаю окошко с ошибкой, которое говорит Process terminated without establishing connection to debugger бла бла бла. Спасибо интернету, гуглу и блогу blog.empiregpservices.com, которые рассказали мне, что нужно бы в конфиге аппликухи сменить версию рантайма.

<application xmlns="http://ns.adobe.com/air/application/1.1">

заменить на

<application xmlns="http://ns.adobe.com/air/application/1.5">

И все заработало.

Update.
Почему-то на JVM 1.6 падает Flex Builder.
Чтобы вручную поставить ему 1.5 заходим в Applications/
Adobe Flex Builder3/Flex Builder.app/Contents/MacOS/FlexBuilder.ini и вставляем сверху следующие две строчки.

-vm
/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0

Что за истерия по поводу HTML5?

Со всех концов интернета только и слышно что про HTML5. Нам обещают настоящую революцию и попутно смерть флэшу. Я прочесал интернеты, проличтал демки и попытался сопоставить кусочки информации и оценить так ли это.

Значит, имеем некоторый стандарт. За все время существования веба мы знаем, что не только каждый старается придумать свою расширенную интерпретацию стандарта, а разные браузеры (по сей день) рендерят один и тот же HTML немного поразному (чем доставляют кучу проблем верстальщикам). Допустим, все новые браузеры договорятся следовать точно этому стандарту и одна отдельная страница в FF, IE, Opera, Chrome, Safari (что еще забыл?) будет выглядеть одинаково. Конечно, есть некоторый сомнения на этот счет, но все же допустим.

Появляется проблема всех новых технологий — малая распространенность поддержки в браузерах. Об этом чуть позже.

Пусть, распространенность новых браузеров такая же как и Flash 9 плагина (что приближается к 100 процентам) и IE6 окончательно сдох. Что я вижу из революционных возможностей HTML5? А ничего.

Вы скажите видео, да новый тэг позволяет вставлять видео плеер парой строчек кода. Так же можно вставить и флэш видео плеер. Бесплатных вагон, а опытные разработчики имеют уже свои готовые проверенные видео-компоненты, перескиновать которые занимает ровно столько же времени, что прописать немного тэгов, яваскрипта и понасохранять картинок. Интересен вопрос кодеков. Во флэше я уверен в том, что текущая версия может играть. А здесь, всем будет устанавливаться кодек принудительно или искаться в системе? Опять же как будет выглядеть embedding на сторонние ресурсы? Огромный кусман HTMLя вставлять себе на страничку? Если отдельно взятый SWF можно легко контролировать, то большинство сайтов к HTML относятся осторожно.

Канва и супер эффекты на ней — это ничего большего, чем куча яваскрипта, который по логике программы мало чем отличается от реализации того же эффекта на флэше. При этом (тут я не уверен конечно) работает медленнее флэша. Демки не впечатляют совершенно.

Пара выводов.

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

HTML5 видео сможет составить конкурецию Flash видео только в том случае, если ведущие видео хостинги перейдут на эту платформу. Кстати говоря, youtube уже имеет подобную страничку, что наводит на некоторые мысли. Вы не знаете кто стоит за youtube (на всякий случай спросил)? За ним стоит Google, а гугл — это, возможно, даже бОльшая сила, чем Microsoft со своим сервелатом и тем более Adobe с флэшем. Все мы помним, как с помощью олимпиады Microsoft заставила установить свой плагин миллионов людей.

Убийца флэш. JavaFX, Silverlight, где они все? Через несколько лет, когда начнут применять HTML5, в Flash Player 12 мы будем иметь нативную поддержку мультитач и полноценный рендеринг 3d аппаратными ускорителями (надеюсь). Adobe тоже не стоит на месте.

Пусть само пишет

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

Так выглядит XML с шаблонами.

&lt;config&gt;
&lt;node name=&quot;const&quot;&gt;
&lt;static var=&quot;0&quot; color=&quot;AAAAAA&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;string&quot;&gt;
&lt;static var=&quot;0&quot; color=&quot;60e18c&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;root&quot;&gt;
&lt;input name=&quot;site&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;site&quot;&gt;
&lt;static text=&quot;site &quot; color=&quot;00FFFF&quot;/&gt;&lt;input name=&quot;name&quot;/&gt;&lt;static text=&quot; {&quot;/&gt;&lt;br/&gt;
&lt;static text=&quot;    &quot;/&gt;&lt;input name=&quot;content&quot;/&gt;&lt;br/&gt;
&lt;static text=&quot;}&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;statement&quot;&gt;
&lt;input name=&quot;statement&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;expression&quot;&gt;
&lt;input name=&quot;expression&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;variable&quot;&gt;
&lt;static text=&quot;var &quot;/&gt;&lt;input name=&quot;name&quot;/&gt;&lt;static text=&quot; = &quot;/&gt;&lt;input name=&quot;value&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;object&quot;&gt;
&lt;static var=&quot;0&quot; color=&quot;00FFFF&quot;/&gt;&lt;static text=&quot;.&quot;/&gt;&lt;input name=&quot;method&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;function&quot;&gt;
&lt;static var=&quot;0&quot; color=&quot;AAAAAA&quot;/&gt;&lt;static text=&quot;( &quot;/&gt;&lt;input name=&quot;parameters&quot;/&gt;&lt;static text=&quot; )&quot;/&gt;
&lt;/node&gt;
&lt;node name=&quot;quotes&quot;&gt;
&lt;static text=&quot;&amp;quot;&quot; color=&quot;60e18c&quot;/&gt;&lt;input name=&quot;string&quot;/&gt;&lt;static text=&quot;&amp;quot;&quot; color=&quot;60e18c&quot;/&gt;
&lt;/node&gt;
&lt;/config&gt;

А так, собственно, код.

q.addNodeText( &quot;:site&quot;, &quot;site&quot;, &quot;site&quot;, 200, 500 );
q.addConstText( &quot;site:name&quot;, &quot;ru.valyard.site&quot;, 200 );
q.addNodeList( &quot;site:content&quot;, &quot;statement&quot; );

var c: String = &quot;site.content&quot;;

q.addText( c+&quot;.0:statement&quot;, &quot;Application&quot;, 200 );
q.addNode( c, &quot;object&quot;, [&quot;Application&quot;], 500 );
q.addNodeText( c+&quot;.0:method&quot;, &quot;function&quot;, &quot;addModules&quot;, 200, 500 );
q.addNodeList( c+&quot;.0.method:parameters&quot;, &quot;expression&quot;, &quot;, &quot; );

var p: String = c+&quot;.0.method.parameters&quot;;
q.addText( p+&quot;.0:expression&quot;, &quot;\&quot;&quot;, 200 );
q.addNode( p, &quot;quotes&quot; );
q.addStringText( p+&quot;.0:string&quot;, &quot;Test&quot;, 200, 500 );
q.addText( p+&quot;.1:expression&quot;, &quot;\&quot;&quot;, 200 );
q.addNode( p, &quot;quotes&quot; );
q.addStringText( p+&quot;.1:string&quot;, &quot;Apple&quot;, 200, 500 );
q.addText( p+&quot;.2:expression&quot;, &quot;\&quot;&quot;, 200 );
q.addNode( p, &quot;quotes&quot; );
q.addStringText( p+&quot;.2:string&quot;, &quot;Warcraft LOL&quot;, 200, 500 );

q.addText( c+&quot;.1:statement&quot;, &quot;var&quot;, 200 )
q.addNode( c, &quot;variable&quot;, null, 500 );
q.addConstText( c+&quot;.1:name&quot;, &quot;module&quot;, 200, 500 );
q.addNodeText( c+&quot;.1:value&quot;, &quot;object&quot;, &quot;Application&quot;, 200, 500 );
q.addNodeText( c+&quot;.1.value:method&quot;, &quot;function&quot;, &quot;loadModule&quot;, 200, 500 );

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