Январь 2011

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

// Создаем новый экземпляр класса Apple var apple = new Apple( );

// Допустимо вызвать метод getCaloriesC ) над экземпляром класса Apple apple. getCalories( );

Для сравнения отметим, что супертип считается несовместимым с подтипом, поскольку программа не может рассматривать экземпляр супертипа как экземпляр подтипа. Например, программа не может вызвать метод hasWorm ( ) классаАрр1е над экземпляром типа данных Food:

// Создаем новый экземпляр класса Food var food = new Food(200);

// Следующая строка приведет к возникновению ошибки обращения. // поскольку класс Food не имеет доступа к методу hasWorm( ) food. hasWorm( ); // Ошибка!

Выявление ошибок несоответствия типов с помощью аннотаций типов

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

: тип

Например, определение переменной с использованием аннотации типа имеет следующий обобщенный вид:

var идентификатор \тип = значение;

В предыдущем коде тип должен быть именем класса или интерфейса (представляющего тип данных) либо специальным символом * (обозначающим «нетипи-зированные» данные).

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

function идентификатор (параметр:типПараметра) -.типВозвращаемогоЗначения {

)

В предыдущем коде аннотация типа параметра задается с помощью указания типа типПараметра, перед которым ставится двоеточие (:); аннотация типа возвращаемого значения задается указанием типа типВозвращаемогоЗначения, перед которым также ставится двоеточие (:). Тип типПараметра должен быть одним из следующих:

? имя класса или интерфейса (представляющего тип данных);

? специальный символ * (обозначающий «нетипизированные» данные).

Тип типВозвращаемогоЗначения должен быть одним из следующих:

? имя класса или интерфейса (представляющего тип данных);

? специальный символ * (обозначающий «нетипизированные» данные);

? специальная, «не возвращающая значение», аннотация типа void (которая обозначает, что функция не имеет возвращаемого значения).

Л_

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

Ш

Аннотация типа для переменной, параметра или результата функции ограничивает значение этой переменной, параметра или результата указанным типом. Способ ограничения значения зависит от используемого режима компиляции кода (как уже было сказано, в компиляторах компании Adobe по умолчанию выбран строгий режим компиляции).

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

Если значение не принадлежит указанному типу данных, то при использовании строгого режима компилятор сгенерирует ошибку (называемую ошибкой несоответствия типов) и прекратит компиляцию кода. При использовании стандартного режима код будет скомпилирован и среда Flash попытается преобразовать значение в указанный тип данных на этапе выполнения программы. Если указанным типом данных является один из внутренних классов String, Boolean, Number, int или uint (называемых примитивными типами), преобразование будет выполнено в соответствии с правилами, описанными в разд. «Преобразование в примитивные типы» этой главы. В противном случае преобразование завершится неудачей и среда Flash сгенерирует ошибку несоответствия типов на этапе выполнения программы. На формальном языке автоматическое преобразование значения на этапе выполнения программы называется приведением.

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

Например, следующий код определяет переменную meal типа Food и присваивает этой переменной экземпляр класса Apple:

var meal:Food = new Apple( ):

Указанный код скомпилируется успешно как в строгом режиме компиляции, так и в стандартном режиме, поскольку класс Apple расширяет Food. В итоге экземпляры класса Apple принадлежат типу данных Food.

В отличие от этого следующий код присваивает переменной meal экземпляр класса VirtualPet:

var meal-.Food = new Vi rtual Pet( «Lucky»):

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

При использовании стандартного режима указанный код будет успешно откомпилирован. Тем не менее, поскольку значение (экземпляр класса VirtualPet) не принадлежит типу данных переменной (Food), среда выполнения Flash попытается привести (то есть преобразовать) значение к типу данных переменной на этапе выполнения программы. В данном случае тип данных переменной не является одним из примитивных типов, поэтому преобразование завершится неудачей и среда Flash сгенерирует ошибку несоответствия типов на этапе выполнения программы.

Рассмотрим другой пример. Следующий код определяет переменную pet Hunger типа int и присваивает этой переменной экземпляр класса VirtualPet:

var pet:Virtual Pet = new VirtualPet(«Lucky»); var petHunger:int = pet:

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

При использовании стандартного режима указанный код будет скомпилирован успешно. Тем не менее, поскольку значение (экземпляр класса VirtualPet) не принадлежит типу данных переменной (int), среда Flash попытается преобразовать значение в тип данных переменной на этапе выполнения программы. В данном слу-

чае тип данных переменной является одним из примитивных типов, поэтому преобразование будет выполнено в соответствии с правилами, описанными в разд. «Преобразование к примитивным типам» этой главы. Таким образом, после выполнения указанного кода значением переменной petHunger будет являться 0.

Разумеется, предыдущий код наверняка разрабатывался не для того, чтобы переменной petHunger присвоить значение 0. Скорее программист просто забыл вызвать метод getHunger ( ) над экземпляром класса VirtualPet, как показано в следующем коде:

var pet-.Virtual Pet = new Vi rtual Pet( «Lucky»); var petHunger:int = pet. getHunger( );

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

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

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

^ I В оставшейся части книги мы будем полагать, что весь код компилируется в строгом м? л п Режиме и Для всех переменных, параметров и возвращаемых значений указываются — Tfey аннотации типа.

Нетипизированные переменные, параметры, возвращаемые значения и выражения

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

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

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

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

var stuff = true:

stuff = new VirtualPetC’Edwin»); // Ошибки нет

I Компилятор языка ActionScript не генерирует ошибки несоответствия типов для нетипи-м$ j „ зированных переменных, параметров и возвращаемых значений.

ipj_

Если программист хочет явно указать, что переменная, параметр или возвращаемое значение намеренно являются нетипизированными, он может использовать специальную аннотацию типа : *. Например, следующий код определяет явно не-типизированную переменную totalCost:

var totalCost:* = 9.99:

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

var totalCost =9.99;

Неявно нетипизированные переменные, параметры и возвращаемые значения обычно используются в тех случаях, когда в программе вообще не применяются аннотации типов, что дает программисту возможность обрабатывать любые типы ошибок на этапе выполнения. Явно нетипизированные переменные, параметры и возвращаемые значения обычно используются в тех случаях, когда программист желает явно указать место в программе, компилируемой в строгом режиме, где допустимо применение нескольких типов данных. Аннотация типа : * позволяет предотвратить появление предупреждения об «отсутствующей аннотации типа» для нетипизированной переменной. Более подробно этот вопрос будет рассмотрен в разд. «Предупреждения об отсутствующих аннотациях типов».

Три особых случая строгого режима

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

? когда нетипизированное выражение присваивается типизированной переменной или параметру либо возвращается из функции с объявленным типом возвращаемого значения;

? если любое выражение присваивается типизированной переменной или параметру, чьим объявленным типом является Boolean, либо возвращается из функции, объявленным типом возвращаемого значения которой является Boolean;

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

Рассмотрим каждый из описанных случаев на примере. Сначала создадим нети-пизированную переменную pet и присвоим ее значение типизированной переменной <±

var pet:* = new Vi rtualPet(«Francis»): pet = new Date( ); var d:Date = pet;

Поскольку переменная pet может содержать значение любого типа, в третьей строке компилятор не сможет определить, принадлежит ли значение переменной pet типу данных Date. Чтобы определить это, код должен быть не только откомпилирован, но и выполнен. Во время исполнения кода среда Flash сможет узнать результат попытки присваивания. В случае с предыдущим кодом значение, хранящееся в переменной pet (присвоенное во второй строке), на самом деле принадлежит типу данных Date (даже несмотря на то, что изначально значение переменной pet, присвоенное в первой строке кода, было несовместимо с типом данных Date). Таким образом, операция присваивания будет выполнена без ошибок.

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

Теперь рассмотрим следующий код, в котором определяется переменная b типа Boolean и этой переменной присваивается целочисленное значение 5:

var b:Boolean = 5;

Даже несмотря на то, что значение 5 не принадлежит типу данных Boolean, компилятор не генерирует ошибку несоответствия типов. Вместо этого он делает предположение, что программист желает привести значение 5 к типу данных Boolean (в соответствии с правилами, описанными в разд. «Преобразование в примитивные типы») и генерирует соответствующее предупреждение. Такая «мягкость» компилятора позволяет сократить количество кода в программе. Например, предположим, что в качестве типа возвращаемого значения метода getHunger ( ) класса VirtualPet указан тип данных Number. Программа может создать переменную, содержащую информацию о том, является животное живым или мертвым, используя следующий код:

var isAlive:Boolean = somePet. getHunger( );

В соответствии с правилами, описанными в разд. «Преобразование в примитивные типы», число 0 преобразуется в значение false, а остальные числа — в значение true. Таким образом, если метод getHunger ( ) возвращает любое значение, отличное от 0, переменной is Alive присваивается значение true; в противном случае переменной is Alive присваивается значение false (животное оказывается мертвым, когда у него не остается калорий).

Для сравнения приведем альтернативный, чуть более длинный код, который пришлось бы использовать в том случае, если бы компилятор проверял типы для переменных типа Boolean (не позволяя преобразовывать их на этапе выполнения программы):

var isAlive:Boolean = somePet. getHunger( ) > 0;

Наконец, рассмотрим код, в котором определяется переменная xCoordinate типа int и этой переменной присваивается значение 4, 6459 типа Number:

var xCoordinate:int = 4.6459;

Даже несмотря на то, что значение 4, 64 5 9 не принадлежит типу данных int, компилятор не генерирует ошибку несоответствия типов. Вместо этого он делает предположение, что вы желаете преобразовать значение 4, б 4 5 9 к типу данных int (в соответствии с правилами, описанными в разд. «Преобразование в примитивные типы»). Это позволяет максимально упростить взаимодействие между числовыми типами данных языка ActionScript.

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

Предупреждения об отсутствующих аннотациях типов

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

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

К счастью, компиляторы языка ActionScript компании Adobe предлагают режим предупреждений, при использовании которого на этапе компиляции сообщается обо всех отсутствующих аннотациях типов. Разработчики могут использовать эти предупреждения для поиска случайно пропущенных аннотаций типов. В приложении Flex Builder и компиляторе mxmlc предупреждения об отсутствующих аннотациях типов включены по умолчанию. В среде разработки Flash предупреждения об отсутствующих типах должны быть включены вручную, для чего используется такая последовательность действий.

1. Используя любой текстовый редактор, откройте файл EnabledWarnings. xml, находящийся в папке /en/Configuration/ActionScript 3.0, которая расположена внутри папки приложения Flash CS3.

2. Найдите следующие строки:

Missing type declaration.

3. Измените enabled=»f alse» на enabled=fftrue».

4. Сохраните файл EnabledWarnings. xml.

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

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

Выявление ошибок обращения на этапе компиляции

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

Например, в следующем коде создается переменная pet типа VirtualPet и этой переменной присваивается экземпляр класса VirtualPet:

var pet:Virtual Pet = new VirtualPet(«Stan»);

Затем в следующем коде происходит попытка обращения к несуществующему методу eatt ( ) через типизированную переменную pet:

pet. eatt(new Sushi( ));

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

1061: Call to a possibly undefined method eatt through a reference with static type zoo-.Virtual Pet.

На русском языке текст ошибки будет следующим: Вызов, вероятно, неопределенного метода eatt через ссылку статического типа zoo:VirtualPet.

Однако стоит отметить, что компилятор не сообщает об ошибках обращения, происходящих в нетипизированных выражениях. Более того, обращения к несуществующим переменным и методам через экземпляры динамических классов (таких как Ob j ect) не приводят к генерации вообще никаких ошибок обращения; вместо этого в результате возвращается значение undefined.

Дополнительную информацию о динамических классах можно найти в гл. 15.

I Существует дополнительное преимущество при использовании аннотаций типов: в прило-м$ а п жении Flex Builder и среде разработки Flash аннотации типов для переменных, параметров fly и возвращаемых значений активизируют подсказки кода. Подсказка кода представляет собой удобное всплывающее меню, содержащее список свойств и методов объектов, которые можно добавить в ваш код путем выбора требуемого элемента.

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

Приведение типов

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

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

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

Рассмотрим следующий код, в котором метод hasWorm ( ) вызывается над объектом Apple через переменную типа Food:

var meal:Food = new Apple( ):

meal. hasWorm( ); // Попытка вызвать метод hasWorm( ) над объектом, // хранящимся в переменной meal

При компиляции предыдущего кода в строгом режиме компилятор должен решить, может ли метод hasWorm ( ) быть вызван над значением переменной meal. Для этого компилятор проверяет, определен ли в классе Food (то есть в классе, который указан в аннотации типа переменной meal) метод hasWorm ( ). В этом классе определение данного метода отсутствует, поэтому компилятор генерирует ошибку обращения. Конечно, глядя на этот код, мы знаем, что значение переменной meal (объект Apple) поддерживает метод hasWorm ( ). Однако этого не знает компилятор. Среда выполнения Flash только на этапе выполнения узнает, что значением переменной на самом деле является объект Apple.

Каково же решение? Использовать операцию приведения типов, чтобы заставить компилятор разрешить предыдущий вызов метода hasWorm ( ). Операция приведения типов приказывает компилятору рассматривать данное значение как принадлежащее указанному типу данных. Эта операция имеет следующий обобщенный вид:

тип{выражение)

В этом коде тип — это любой тип данных, а выражение — любое выражение. Говоря простым языком, эта операция «приводит выражение к указанному типу тип». Например, следующий код приводит выражение meal к типу данных Apple перед вызовом метода hasWorm ( ) над значением переменной meal: Apple(meal).hasWorm( )

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

Независимо от действительного значения переменной meal компилятор верит, что типом данных выражения meal является тип Apple. По этой причине, принимая решение о возможности вызова метода hasWorm ( ) над значением переменной meal, компилятор проверяет, определен ли метод hasWorm ( ) в классе Apple, но не в классе Food. Метод hasWorm ( ) определен в классе Apple, и следовательно, компилятор не генерирует никаких ошибок.

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

тип, то среда Flash просто возвращает этот объект. Однако если выражение выражение преобразуется в объект, который не принадлежит указанному типу тип, возможен один из двух вариантов завершения операции приведения типов. Если указанный тип тип не является примитивным, операция приведения типов вызовет ошибку на этапе выполнения; в противном случае значение объекта преобразуется в указанный тип (в соответствии с правилами, перечисленными в разд. «Преобразование в примитивные типы»), и результатом операции будет преобразованное значение.

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

var meal:Food = new Applet );

Apple(meal); // На этапе выполнения вернет объект Apple

Для сравнения, в следующем коде значение переменной meal, сформированное на этапе выполнения программы, не принадлежит типу данных VirtualPet, и, поскольку тип данных VirtualPet не является примитивным, операция приведения типов во второй строке вызовет ошибку типа:

var meal:Food = new Apple( );

Vi rtualPet(meal); // На этапе выполнения будет вызвана ошибка типа

Наконец, в следующем коде значение переменной meal, сформированное на этапе выполнения программы, не принадлежит типу данных Boolean, но, поскольку тип данных Boolean является примитивным, операция приведения типов во второй строке преобразует значение переменной meal в указанный тип и вернет результат данного преобразования (true):

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

Var meal:Food = new Apple( );

Boolean(meal): // На этапе выполнения будет возвращено значение true

Избавление от нежелательных ошибок несоответствия типов

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

В качестве примера представьте программу, которая преобразует температуру, заданную по шкале Фаренгейта, в температуру по шкале Цельсия. Значение температуры по шкале Фаренгейта вводится в текстовое поле, представленное экземпляром внутреннего класса TextField. Для получения введенного значения мы обращаемся к переменной text экземпляра класса TextField, как показано в следующем коде:

var fahrenheit:Number = inputField. text;

В данных условиях такой код вызовет ошибку несоответствия типов, поскольку типом данных переменной text является String. Чтобы избавиться от этой ошибки, мы используем операцию приведения типов, как показано в следующем коде:

var fahrenheit:Number = NumberCinputField. text):

На этапе выполнения программы этот код преобразует строковое значение, хранящееся в переменной inputField. text, в тип Number и присвоит преобразованное значение переменной fahrenheit.

Восходящее и нисходящее приведения типов

Приведение типа объекта к одному из его супертипов (суперклассу или суперинтерфейсу) называется восходящим приведением типов. Например, следующая операция осуществляет восходящее приведение типов, поскольку тип данных Food является супертипом типа Apple:

Food(new Apple( ))

И наоборот, приведение типа объекта к одному из его подтипов (подклассу или подинтерфейсу) называется нисходящим приведением, поскольку эта операция выполняет приведение типа объекта к типу, который находится ниже текущего в иерархии. Следующая операция осуществляет нисходящее приведение типов, поскольку тип данных Apple является подтипом типа Food:

Apple(new Food( ))

Говорят, что восходящее приведение типов «расширяет» тип объекта, поскольку супертип является более обобщенным по сравнению с его подтипом. В то же время нисходящее приведение типов «сужает» тип объекта, поскольку подтип является более специализированным, чем его супертип.

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



Полезные ссылки
Случайные записи
  • 02.09.2010">Тенденции развития веб-дизайна.
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 070
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.86
  • 15.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.37
  • 14.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.73
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.93
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.126
  • 16.03.2011">Руководство по actionscript. часть 3, стр. 026
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.37
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 065
  • 04.03.2011">Руководство по actionscript. часть 5, стр. 035
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.48
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 045
  • 27.02.2011">Руководство по actionscript. часть 6, стр. 049
  • 04.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.5
Опрос

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

View Results

Loading ... Loading ...