Руководство по actionscript. часть 2, стр. 107

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

package { import flash. events.*: import flash. utils.*:

public class ImageLoader { private var loadlnterval:int;

public function ImageLoader (delay:int = 1000) { loadlnterval = setlnterval(loadlmage. delay);

}

public function loadlmage ( ):void { traceC’Now loading image…»); // Код загрузки изображения // здесь не приводится

}

}

}

Теперь представьте, что основной класс приложения SlideShow реализует функциональность для запуска и остановки слайд-шоу. Для запуска слайд-шоу класс SlideShow создает экземпляр класса ImageLoader, управляющего процессом загрузки изображений. Экземпляр класса ImageLoader сохраняется в переменной экземпляра imgLoader, как показано в следующем коде: «

imgLoader = new ImageLoader( );

Для остановки или приостановки слайд-шоу класс SlideShow удаляет ссылку на экземпляр класса ImageLoader, как показано в следующем коде:

imgLoader = null;

Когда переменной imgLoader присваивается значение null, экземпляр класса ImageLoader становится доступным для сборки мусора. Тем не менее, до тех пор пока этот экземпляр не будет фактически удален из системной памяти, операция загрузки в экземпляре ImageLoader, реализованная на базе функции setlnterval ( ), будет регулярно выполняться.

Руководство по actionscript. часть 2, стр. 108

Это демонстрирует следующий очень простой класс. Он создает экземпляр класса ImageLoader и сразу же удаляет ссылку на созданный экземпляр. Но даже после того, как переменной imgLoader присвоено значение null, сообщение «Now loading image…» продолжает появляться в окне для отладки с интервалом один раз в секунду.

package { import flash. display.*;

public class SlideShow extends Sprite { private var imgLoader:ImageLoader; public function SlideShow ( ) {

// Создаем экземпляр класса ImageLoader и сразу же удаляем ссылку

// на созданный экземпляр

imgLoader = new ImageLoader( );

imgLoader = null:

}

}

}

Если объем памяти, который необходим приложению для демонстрации изображений в режиме слайд-шоу, никогда не достигнет уровня, достаточного для запуска цикла сборки мусора, операция загрузки в экземпляре класса ImageLoader, реализованная на базе функции set I nterval ( ), будет выполняться бесконечно долго. Ненужное выполнение кода в «заброшенном» экземпляре класса ImageLoader тратит впустую системные и сетевые ресурсы и может привести к появлению нежелательных побочных эффектов в программе.

Чтобы избежать ненужного выполнения кода в «заброшенных» объектах, программа должна всегда деактивировать объекты перед тем, как избавиться от них. Деактивация объекта означает его перевод в нерабочее состояние, когда программа больше не может воспользоваться этим объектом для выполнения кода. Например, чтобы деактивировать объект, мы могли бы выполнить одно из перечисленных далее действий или же все действия сразу:

? отменить регистрацию методов объекта для событий;

? остановить все таймеры и интервалы;

? остановить воспроизводящую головку временных шкал (для экземпляров клипов, созданных в среде разработки Flash);

? деактивировать любые объекты, которые станут недостижимыми после того, как сам объект станет недостижимым.

Руководство по actionscript. часть 2, стр. 109

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

Например, наш предыдущий класс ImageLoader должен определить метод, останавливающий внутренний интервал. Сейчас добавим подобный метод и назовем его dispose ( ). Имя выбрано произвольно; с таким же успехом мы могли бы присвоить данному методу имя kill ( ), destroy ( ), die ( ), clean ( ), disable ( ), deactivate ( ) или любое другое имя. Рассмотрим этот код:

package { import flash. events.*; import flash. utils.*;

public class ImageLoader { private var loadlnterval:int;

public function ImageLoader (delay;int = 1000) { loadlnterval =-setlnterval (loadlmage. delay);

}

public function loadlmage ( ):void { traceC’Now loading image…»); // Код загрузки изображения не приводится

}

public function dispose ( ):void { clearlnterval(loadlnterval);

}

}

}

Любой код, создающий экземпляр класса ImageLoader, должен в дальнейшем вызвать метод ImageLoader. dispose ( ) перед тем, как избавиться от этого экземпляра, как показано в следующем коде:

package { import flash. display.*;

public class SlideShow extends Sprite { private var imgLoader:ImageLoader; public function SlideShow ( ) {

// Создаем и сразу же избавляемся от экземпляра класса ImageLoader

imgLoader = new ImageLoader( );

imgLoader. dispose( );

imgLoader = null;

}

}

Сборка мусора в действии

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

мусора исходный объект Sprite будет удален из памяти и его сообщения перестанут появляться в консоли для отладочной информации.

Руководство по actionscript. часть 2, стр. 110

Листинг 14.1. Сборка мусора в действии

package { import flash. display.*; import flash. text.*; import flash. utils.*; import flash. events.*; import flash. system.*;

public class GarbageCollectionDemo extends Sprite { public function GarbageCollectionDemo ( ) { // Данный объект Sprite будет удален в процессе сборки мусора, когда // объем потребленной памяти превысит допустимое значение var s.-Sprite = new Sprite( ):

s. addEventLi stener(Event. ENTER_FRAME. enterFrameLi stener);

// Многократно создает новые объекты, занимая. системную память var timer:Timer = new Timerd. 0); timer. addEventListener(TimerEvent. TIMER, timerListener); timer. start( );

}

private function timerListener (e:TimerEvent):void { // Создаем объект, чтобы захватить часть системной памяти. Это может // быть любой объект, но объекты класса TextField являются довольно // объемными, new TextFi eld( );

}

// Эта функция выполняется до тех пор. пока объект Sprite не будет

// удален из памяти в процессе сборки мусора

private function enterFrameListener (e:Event):void { // Отображаем объем памяти, занимаемой программой traceC’System memory used by this program: » + System. total Memory);

}

}

К задворкам языка ActionScript

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

Руководство по actionscript. часть 2, стр. 111

Более полную информацию по сборке мусора в языках программирования можно получить в специальной статье на сайте «Википедии» и на сайте The Memory Management Reference по адресу http://www. memorymanagement. org.

Несколько самостоятельно опубликованных статей, написанных Грантом Скинне-ром (Grant Skinner) и посвященных сборке мусора в языке ActionScript 3.0, можно найти на сайте автора по адресу http://gskinner. com/talks/resource-managemenry и http:// www. gskinner. com/blog/archives/2006/06/as3_resource_ma. html.

В следующей главе мы рассмотрим менее распространенные инструменты языка ActionScript, предназначенные для изменения структуры классов и объектов на этапе выполнения программы.

ПИВА 16

Динамические возможности языка ActionScript

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

Изначально язык ActionScript позволял динамически, на этапе выполнения программы, изменять структуры всех классов и даже любых отдельных объектов. Например, на этапе выполнения программа могла:

? добавлять новые методы или переменные экземпляра в любой класс;

? добавлять новые методы или переменные экземпляра в любой отдельно взятый конкретный объект;

? создавать новый класс с нуля;

? изменять суперкласс выбранного класса.

С появлением языка ActionScript 3.0, приложений Flash Player 9, Adobe AIR и Flex, платформа Flash вышла на новый уровень развития, где сложность программы, разработанной на языке ActionScript, может вполне конкурировать со сложностью полнофункционального настольного приложения. Соответственно, ActionScript, как настоящий язык программирования, взял на вооружение многие формальные структуры, необходимые для разработки крупномасштабных приложений, например формальное ключевое слово class и синтаксис наследования, формальные типы данных, систему предопределенных событий, обработку исключений и встроенную поддержку формата XML. Тем не менее динамические возможности ActionScript остаются доступными и по-прежнему составляют важную часть внутренней структуры языка.

В этой главе рассматриваются приемы программирования с использованием динамических возможностей языка ActionScript. Однако стоит отметить, что гибкость, присущая такому программированию, ограничивает или полностью лишает преимущества проверки типов, с которым мы познакомились в гл. 8. Как результат, большинство сложных программ используют описанные в этой главе возможности лишь изредка, если вообще используют. Например, из более чем 700 классов, определенных в среде разработки Flex, только около 10 классов используют возможности динамического программирования. С другой стороны, даже если вы никогда не будете использовать динамическое программирование в своем коде, информа-

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

Руководство по actionscript. часть 2, стр. 112

В качестве нашего первого приема динамического программирования мы рассмотрим динамические переменные экземпляра — переменные, добавляемые в конкретный объект на этапе выполнения программы.

Динамические переменные экземпляра

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

Что же произойдет, если владелец одного из самолетов решит закрепить собственный фонарь на верху своего самолета? Этот самолет будет обладать специфической характеристикой, не присущей всем остальным самолетам. В языке ActionScript «добавление нового фонаря на конкретный самолет» аналогично добавлению новой переменной экземпляра в отдельно взятый конкретный объект, при этом в остальные экземпляры класса данного объекта этот «фонарь» не добавляется. Переменная экземпляра такого рода называется динамической переменной экземпляра. В сравнении с динамическими переменными экземпляра «обычные» переменные экземпляра называются фиксированными.

Динамические переменные экземпляра могут быть добавлены только в экземпляры классов, объявленных с использованием атрибута dynamic (подобные классы называются динамическими). Динамические переменные экземпляра не могут быть добавлены в экземпляры классов, которые не объявлены с использованием атрибута dynamic (подобные классы называются закрытыми). Подкласс динамического класса считается динамическим только в том случае, если его определение тоже включает атрибут dynamic.

Следующий код создает новый класс Person, который может представлять человека в статистической программе, отслеживающей демографическую«ситуацию. Поскольку класс Person объявлен с использованием атрибута dynamic, в любой отдельный объект класса Person на этапе выполнения программы можно добавлять динамические переменные экземпляра.

dynamic public class Person { }

После того как класс будет объявлен динамическим, мы сможем добавлять новые динамические переменные в любой экземпляр этого класса с помощью стандартного оператора присваивания. Например, следующий код добавляет динамическую переменную экземпляра eyeColor в объект класса Person:

var person.-Person = new Person( ); person. eyeColor = «brown»;

Как уже известно из гл. 8, если бы класс Person не был объявлен с использованием атрибута dynamic, приведенный код вызвал бы ошибку обращения, поскольку в классе Person не определена переменная экземпляра с именем eyeColor. Тем не менее в данном случае класс Person объявлен с использованием атрибута dynamic. В результате, когда среда выполнения Flash попытается присвоить значение несуществующей переменной экземпляра eyeColor, вместо того чтобы сообщить об ошибке, она просто создаст динамическую переменную экземпляра с именем eyeColor и присвоит ей указанное значение («brown»). Обратите внимание, что определение динамической переменной экземпляра в предыдущем коде не содержит и не должно содержать объявление типа и модификатор управления доступом.

I Все динамические переменные экземпляра являются нетипизированными и открытыми.

-

Следующий код, в котором происходит попытка использовать объявление типа при создании переменной eyeColor, вызовет ошибку на этапе компиляции:

person. eyeColor:String = «brown»; // Ошибка! Использование :Stri ng здесь

// недопустимо

Для получения значения динамической переменной экземпляра применяется стандартное выражение доступа к переменной, как показано в следующем коде:

trace(person. eyeColor); // Выводит: brown

Если указанная переменная экземпляра (динамическая или нединамическая) не существует, среда выполнения Flash вернет значение undefined, как показано в следующем коде:

trace(person. age); // Выводит undefined, поскольку объект person // не имеет переменной экземпляра с именем age

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

Руководство по actionscript. часть 2, стр. 113

Динамические переменные экземпляра иногда используются для создания простой «справочной таблицы», рассматриваемой далее, в разд. «Использование динамических переменных экземпляра для создания справочных таблиц».

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

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

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

Обработка динамических переменных экземпляра с помощью циклов for-each-in и for-in. Цикл f or-each-in обеспечивает простой способ обработки значений динамических переменных экземпляра объекта (или элементов массива). Он имеет следующий общий вид:

for each (переменнаяИлиЗначениеЭлемента in некийОбьект) { инструкции

}

Инструкции инструкции цикла f or-each-in выполняются один раз для каждой динамической переменной экземпляра или элемента массива в объекте некийОбьект. В процессе каждой итерации цикла значение переменной или элемент, над которым выполняется итерация (перечисление), присваивается переменной переменнаяИлиЗначениеЭлемента. Код внутри тела цикла имеет возможность применять это значение по своему усмотрению.

Например, рассмотрим описание объекта и связанный с ним цикл f or-each-in, продемонстрированный в следующем коде. Обратите внимание, что внутренний объект Object объявлен с использованием атрибута dynamic и, следовательно, поддерживает динамические переменные экземпляра.

var info:Object = new ObjectC ); info. city = «Toronto»; info. country = «Canada»;

for each (var detail:* in info) { trace(detail);

}

Приведенный цикл выполняется дважды, по одному разу для каждой из двух динамических переменных экземпляра объекта, на который ссылается переменная info. При выполнении цикла в первый раз переменной detail присваивается значение «Toronto» (то есть значение переменной city). При выполнении цикла во второй раз переменная detail содержит значение «Canada» (то есть значение переменной country). Таким образом, в результате выполнения цикла будет выведена следующая информация:

Toronto Canada

В большинстве случаев порядок, в котором циклы for-each-in и for-in перечисляют переменные объекта, не гарантирован. Однако существует два исключения: перечисление переменных экземпляров классов XML и XMLList происходит в возрастающем порядке, в соответствии с числовыми именами их переменных (то есть в соответствии с документированным порядком для объектов XML; дополнительную информацию можно найти в гл. 18). Для всех остальных типов объектов порядок перечисления, используемый циклами for-each-in и for-in, может отличаться в зависимости от версий языка ActionScript и клиентских сред выполнения Flash. Таким образом, не следует писать код, который зависит от порядка перечисления циклов for-each-in или for-in, кроме тех случаев, когда обрабатываются данные в формате XML.

Руководство по actionscript. часть 2, стр. 114

Следующий код демонстрирует цикл for-each-in, который используется для обращения к значениям элементов массива:

var games:Array = ["Project Gotham Racing", "Shadow of the Colossus", "Legend of Zelda"]:

for each (var game:* in games) { trace(game);

}

Приведенный цикл выполняется трижды, по одному разу для каждого из трех элементов массива games. При выполнении цикла в первый раз переменной game присваивается значение «Project Gotham Racing» (то есть значение первого элемента). При выполнении цикла во второй раз переменная game принимает значение «Shadow of the Colossus», а на третий раз — значение «Legend of Zelda». Таким образом, выводимая информация выглядит следующим образом:

Project Gotham Racing Shadow of the Colossus Legend of Zelda

Цикл for-each-in является напарником цикла for-in языка ActionScript. Тогда как цикл for-each-in перечисляет значения переменных, цикл for-in — имена переменных. Например, следующий цикл for-in перечисляет имена динамических переменных экземпляра объекта, на который ссылается переменная info:

for (var detailName:* in info) { trace(detailName);

}

// Вывод: // city // country

Обратите внимание, что предыдущий код выводит имена переменных city и country, а не их значения. Для обращения к значениям этих свойств мы могли бы использовать оператор [ ], который рассматривается далее, в разд. «Динамические обращения к переменным и методам». Это демонстрирует следующий код:

for (var detailName:* in info) { trace(i nfo[detai1 Name]);

}

// Вывод:

// Toronto // Canada

Чтобы исключить перечисление динамической переменной экземпляра в циклах for-in и for-each-in, используется метод setPropertylsEnumerable ( ) класса Ob j ect, показанный в следующем коде:

info. setPropertylsEnumerableC’city», false);

for (var detailName:* in info) { trace(info[detailName]);

}

// Выводит: Canada

// (переменная «city» не была обработана в цикле for-in)

Мы рассмотрим применение цикла for-each-in на практическом примере в разд. «Использование динамических переменных экземпляра для создания справочных таблиц».

Руководство по actionscript. часть 2, стр. 115

Динамическое добавление нового поведения в экземпляр

Когда вы познакомитесь с тем, как создавать динамические переменные экземпляра, у вас может возникнуть вопрос, поддерживает ли язык ActionScript и динамические методы экземпляра, то есть добавление нового метода экземпляра в один конкретный объект без добавления этого метода в любые другие экземпляры класса данного объекта. Фактически формальных способов для динамического добавления настоящего метода экземпляра в объект не существует. Тем не менее, присвоив замыкание функции динамической переменной экземпляра, мы можем имитировать эффект добавления нового метода в отдельный объект (чтобы освежить в памяти смысл фразы «замыкание функции», обратитесь к гл. 5). Следующий код демонстрирует общий подход:

некийОбъект. некаяДинамическаяПеременная = некаяФункция;

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

некийОбъект. некаяДинамическаяПеременная = function (параметр1, параметр2… параметрп) { II Тело функции

}

После того как функция некаяФункция будет присвоена динамической переменной экземпляра, она может быть вызвана через этот объект точно так же, как и обычный метод экземпляра, что показано в следующем коде:

некийОбъект. некаяДинамическаяПеременная(значение1, значение2. . . значениеп);

Чтобы продемонстрировать использование предыдущего общего синтаксиса, вернемся к примеру с переменной info из предыдущего раздела:

var info:Object = new Object( ); info. city = «Toronto»; info. country = «Canada»;

Предположим, мы хотим добавить в объект, на который ссылается переменная info, новое поведение — возможность форматировать и отображать собственное содержимое в виде строки. Мы создадим новую переменную экземпляра get Address, которой присвоим желаемую функцию форматирования, как показано в следующем коде:

info. getAddress = function ( ):String { return this. city + «, » + this. country;

}

Для вызова этой функции используется следующий код:

trace(info. getAddress( ));

Обратите внимание, что внутри тела функции, присвоенной переменной get Address, мы можем использовать ключевое слово this для обращения к переменным и методам объекта, через который вызывается эта функция. На самом деле в случае с замыканиями функций обратиться без использования ключевого слова this к переменным и методам объекта, через который вызывается эта функция, невозможно. Предположим, мы убрали ключевое слово this из описания функции getAddress ( ), как показано в следующем коде:

info. getAddress = function ( ):String { return city + «, » + country;

}

При поиске переменных city и country среда выполнения Flash не рассматривает автоматически переменные экземпляра объекта, на который ссылается переменная info. Следовательно, предыдущий код вызовет ошибку (если выше в цепочке видимости функции getAddress ( ) не существует других переменных с именами city и country).

Руководство по actionscript. часть 2, стр. 116

Если функция переменной экземпляра объекта присваивается внутри класса данного объекта, то она сможет обращаться к переменным и методам объекта, объявленным с использованием модификаторов управления доступом private, protected, internal и public. Если присваивание происходит внутри подкласса класса объекта, функция сможет обращаться только к тем переменным и методам объекта, которые объявлены с использованием модификаторов управления доступом protected, internal и public. Если присваивание происходит внутри пакета, в котором объявлен класс объекта, функция сможет обращаться только к переменным и методам объекта, объявленным с использованием модификаторов управления доступом internal и public. Если класс объекта объявлен в одном пакете, а присваивание происходит в другом пакете, функция сможет обращаться только к переменным и методам объекта, объявленным с использованием модификатора управления доступом public.

Например, рассмотрим следующий код, который создает динамический класс

Employee:

dynamic public class Employee { public var startDate:Date; private var age:int;

}

Следующий код присваивает функцию динамической переменной экземпляра doReport экземпляра класса Employee. Присваивание происходит за пределами класса Employee, но внутри класса, который объявлен в том же пакете, что и класс Employee. Следовательно, функция может обращаться только к тем переменным объекта Employee, которые объявлены с использованием модификаторов управления доступом internal й public. Переменные, объявленные с использованием модификаторов управления доступом protected и private, недоступны для этой функции.

public class Report { public function Report (employeeEmployee) { // Присваиваем функцию переменной doReport employee. doReport = function ( ):void { trace(this. startDate); // Обращение к public-переменной допустимо trace(this. age); // Обращение к private-переменной запрещено

Динамические обращения к переменным и методам

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

некийОбъект\_некоеВыражение]

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

Например, следующий код присваивает значение «Toronto» переменной, имя которой указывается с помощью выражения строкового литерала «city»:

var info:Object = new Object( ); info["city"] = «Toronto»;

Следующий код присваивает значение «Canada» переменной, имя которой указывается с помощью выражения строкового литерала «country»: info["country"] = «Canada»;

Следующий код получает значение переменной, имя которой указывается с помощью выражения-идентификатора detail:

var detail-.String = «city»; trace(info[detail]); // Выводит: Toronto

Когда среда выполнения Flash встречает код info [detail], она сначала определяет значение переменной detail (в нашем случае это «city»), после чего ищет переменную с именем «city» в объекте, на который ссылается переменная info.



Полезные ссылки
Случайные записи
  • 01.01.2010">14 бесплатных шрифтов в стиле Web 2.0
  • 04.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.23
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 069
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 021
  • 24.02.2011">Руководство по actionscript. часть 6, стр. 108
  • 04.03.2011">Руководство по actionscript. часть 5, стр. 035
  • 03.03.2011">Руководство по actionscript. часть 5, стр. 077
  • 07.03.2011">Руководство по actionscript. часть 4, стр. 104
  • 17.03.2011">Руководство по actionscript. часть 3, стр. 004
  • 07.03.2011">Руководство по actionscript. часть 4, стр. 110
  • 18.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.103
  • 15.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.52
  • 19.03.2011">Руководство по actionscript. часть 2, стр. 089
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.107
  • 21.03.2010">Интересные заметки за февраль
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...