Январь 2011

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

Зованием модификатора internal, может быть доступна только внутри пакета, в котором была описана.

Модификаторы protected и private накладывают еще большие ограничения, чем модификатор internal. Переменная экземпляра, объявленная с использованием модификатора protected, может быть доступна только для кода класса, содержащего описание этой переменной, или для кода потомков этого класса (мы еще не рассматривали наследование, поэтому, если вы незнакомы с объектно-ориентированным программированием, пока не обращайте внимания на этот модификатор). Переменная экземпляра, объявленная с использованием модификатора private, может быть доступна только для кода класса, содержащего описание этой переменной. Если при объявлении переменной никакой модификатор не указан, то используется модификатор internal (доступ внутри пакета).

Модификаторы управления доступом для переменных экземпляра перечислены в табл. 1.2.

Таблица 1.2. Модификаторы управления доступом переменной экземпляра

Атрибут

Размещение кода public internal protected private

Код в классе, содержащем описание переменной Доступна Доступна Доступна Доступна

Код в потомке класса, содержащего описание переменной Доступна Доступна Доступна Недоступна

Код в другом классе, принадлежащем пакету с описанием переменной Доступна Доступна Недоступна Недоступна

Код не принадлежит пакету с описанием переменной Доступна Недоступна Недоступна Недоступна

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

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

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

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

с использованием модификатора управления доступом internal, как показано в следующем коде:

package zoo { internal class VirtualPet { internal var petName = «Unnamed Pet»;

}

}

Обратите внимание, что описание переменной экземпляра с использованием атрибута internal аналогично описанию переменной без использования какого-либо модификатора управления доступом (поскольку модификатор internal применяется по умолчанию).

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

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

Параметры и аргументы конструктора

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

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

class НекийКласс { function НекийКласс {идентификатор = значение) {

)

}

В данном коде идентификатор — это имя параметра конструктора, а значение — исходное значение параметра.

Если возникает необходимость описать несколько параметров в методе-конструкторе, то их имена перечисляются через запятую, как показано в обобщенном коде ниже (обратите внимание на разрывы строк, которые не только допустимы, но и широко распространены):

class НекийКласс { function НекийКласс {идентификатор! = значение1, идентификатор2 = значение2,

идентификаторЗ = значвнивЗ) {

}

}

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

new НекийКласс(значение1, значение2, значениеЗ)

В этом коде значение^ значение2 и значениеЗ — это значения, присваиваемые в указанном порядке параметрам метода-конструктора класса НекийКласс. Значение, присваиваемое параметру конструктора при создании объекта (как показано в предыдущем коде), называется аргументом конструктора. Использование аргумента конструктора в качестве значения параметра конструктора называется передачей этого значения конструктору.

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

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

class НекийКласс { function НекийКласс (обязательныйПараметр) { }

}

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

new НекийКласс(значение)

Отсутствие аргумента конструктора для обязательного параметра приведет к ошибке либо на этапе компиляции программы (если для компиляции выбран строгий режим), либо на этапе выполнения программы (если программа была откомпилирована в стандартном режиме). Различия между строгим и стандартным режимами компиляции будут рассмотрены в гл. 7.

Ш4_ Q При создании нового объекта без аргументов конструктора некоторым программистам 1 нравится оставлять пустые круглые скобки. Например, многие разработчики предпочи-— тают записывать

new Virtual Pet( ) а не

new VirtualPet

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

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

Используя в качестве примера предыдущий обобщенный код, описывающий метод-конструктор класса с параметром, добавим новый метод-конструктор в класс VirtualPet и опишем один обязательный параметр конструктора — name. Значение параметра name будет присвоено переменной экземпляра petName каждого объекта VirtualPet.

Рассмотрим основной код, содержащий описание нового метода-конструктора без каких-либо инструкций:

package zoo { internal class VirtualPet { internal var petName = «Unnamed Pet»;

public function VirtualPet (name) {

}

}

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

package zoo { public class VirtualZoo { public function VirtualZoo ( ) { var pet = new VirtualPet; pet. petName = «Stan»;

}

}

}

Это же обновленная версия, в которой значение Stan передается конструктору класса VirtualPet, а не присваивается переменной petName созданного экземпляра:

package zoo { public class VirtualZoo { public function VirtualZoo ( ) { var pet = new VirtualPetC’Stan»);

}

}

}

В этом коде при создании экземпляра класса VirtualPet выполняется конструктор этого класса и аргумент конструктора Stan присваивается параметру name. Из этого следует, что внутри конструктора класса VirtualPet параметр name можно использовать для присваивания значения Stan переменной экземпляра petName нового объекта VirtualPet. Для этого необходимо указать значение переменной petName, используя выражение идентификатора.

Выражения и выражения идентификатора рассматриваются в следующем разделе.

Выражения

Представление значения в исходном коде программы на ActionScript называется выражением. Например:

new Date( )

Здесь new — выражение, представляющее новый объект (в данном случае объект Date).

Подобным же образом следующий код демонстрирует константное выражение, представляющее объект Number со значением 2.5:

2.5

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

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

К примеру, оператор умножения, используемый для нахождения произведения двух чисел, записывается с помощью символа *. Следующий код демонстрирует составное выражение для умножения числа 4 на число 2,5:

4 * 2.5

При выполнении этого кода вычисляется результат произведения и все составное выражение (4 * 2.5) заменяется одним результатом вычисления (10). Процесс определения значения выражения называется его вычислением.

С полным списком операторов языка ActionScript можно ознакомиться в гл. 10.

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

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

quantity * price

Переменные quantity и price являются своего рода контейнерами для значений, которые будут определены в процессе выполнения программы. Значение переменной quantity, например, может задаваться пользователем, а значение переменной price может быть получено из базы данных. Далее предположим, что переменной quantity присвоено значение 2, а переменной price — значение 4.99. При вычислении выражения quantity * price программа заменит имя переменной

quantity значением 2, а имя переменной price — значением 4 . 9 9. Таким образом, в процессе вычисления это выражение будет заменено следующим:

2 * 4.99

Окончательным результатом выражения является значение 9.98.

Л_

Говоря формальным языком, выражение, состоящее только из одного имени переменной, например quantity, называется выражением идентификатора.

Теперь попробуем применить выражение идентификатора в программе по созданию виртуального зоопарка.

Присваивание одной переменной значения другой переменной

В процессе написания кода программы мы остановились на создании метода-конструктора для класса VirtualPet. Метод-конструктор описывает единственный параметр name, значение которого определяется во внешнем коде, отвечающем за создание объекта в классе VirtualZoo. Ниже представлен исходный код классов VirtualPet и VirtualZoo, включающий в себя все произведенные ранее изменения:

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

// Класс VirtualPet package zoo { internal class VirtualPet { internal var petName = «Unnamed Pet»;

public function VirtualPet (name) { }

}

}

// Класс VirtualZoo package zoo { public class VirtualZoo { public function VirtualZoo ( ) { var pet = new VirtualPetC’Stan»):

}

}

}

Теперь, после того как мы ознакомились с процессом применения переменных в выражениях, параметр name может быть использован для присвоения значения Stan переменной экземпляра petName нового объекта VirtualPet.

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

объект. переменнаяЭкземпляра = значение

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

_j$_

йЪь щ В теле метода-конструктора создаваемый объект называется текущим. Для обращения ¦г? Л к нему применяется ключевое слово this.

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

this. petName

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

this. petName = value

В нашем случае присваиваемым значением является значение параметра name. Таким образом, вместо слова value просто подставляется имя параметра name:

this. petName = name

На этапе выполнения среда Flash (в которой выполняется программа) заменит параметр name из предыдущего кода значением, переданным конструктору класса VirtualPet. Это значение впоследствии будет присвоено переменной экземпляра petName.

Код класса VirtualPet с внесенными изменениями выглядит следующим образом:

package zoo { internal class VirtualPet { internal var petName = «Unnamed Pet»;

public function VirtualPet (name) { this. petName = name;

}

}

}

Теперь, когда значение переменной экземпляра petName присваивается в конструкторе класса VirtualPet, ненужное исходное значение Unnamed Pet, указанное в описании переменной petName, может быть удалено. Описание переменной petName до настоящего момента выглядело следующим образом:

internal var petName = «Unnamed Pet»;

После изменений описание этой переменной примет следующий вид (обратите внимание на отсутствие инициализатора переменной):

package zoo { internal class VirtualPet { internal var petName;

}

public function VirtualPet (name) { this. petName = name;

}

Выражение, которое используется для присваивания значения переменной, например this. petName = name, называется выражением присваивания. В качестве знака равенства в таких выражениях применяется оператор, называемый оператором присваивания.

Копии и ссылки. В предыдущем разделе был описан процесс присваивания значения одной переменной другой. В частности, переменной экземпляра petName было присвоено значение параметра name. Вот этот код:

this. petName = name;

Результат присваивания значения одной переменной другой зависит от типа присваиваемого значения.

В случаях, когда значением переменной-источника в выражении присваивания является экземпляр класса String, Boolean, Number, int или uint, среда выполнения создает копию этого значения и присваивает созданную копию целевой переменной. После окончания процедуры присваивания в системной памяти образуются две независимые версии исходного значения — само исходное значение и его копия. Переменная-источник указывает, или ссылается, на первоначальное значение в памяти. Целевая переменная ссылается на новое значение в памяти.

В других случаях, когда значением переменной-источника в выражении присваивания выступает экземпляр пользовательского класса или экземпляр предопределенного класса языка ActionScript, за исключением классов String, Boolean, Number, int или uint, программа связывает вторую переменную непосредственно со значением первой. После присваивания в памяти будет существовать только одна копия значения, на которую будут ссылаться обе переменные. В подобной ситуации говорят, что переменные совместно используют ссылку на один объект в памяти. Очевидно, что изменения, вносимые в объект через первую переменную, будут доступны и для второй переменной. Например, рассмотрим код, в котором создаются две локальные переменные — а и Ь, после чего значение переменной а присваивается переменной Ь.

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

Var а = new VirtualPet(«Stan»); var b = a;

В процессе выполнения первой строки приведенного выше кода средой Flash будет создан новый объект класса VirtualPet, после этого он будет записан в память и связан с локальной переменной а. В результате выполнения второй строки кода объект VirtualPet, на который уже ссылается переменная а, будет связан с локальной переменной Ь. Изменения, вносимые в объект VirtualPet через переменную а, будут естественным образом отражаться на переменной Ь, и наоборот. Например, если переменной экземпляра petName присвоить новое значение, используя код b. petName = «Tom», а затем обратиться к этой переменной с помощью конструкции a. petName, то будет получено то же значение — Тот.

Или, если переменной экземпляра petName присвоить значение, используя код а. petName = «Ken», а затем обратиться к данной переменной с помощью конструкции b. petName, будет получено то же значение — Ken.

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

Переменная экземпляра для нашего животного

В одном из предыдущих разделов было сказано, что в тот момент, когда метод или функция, в которой описана локальная переменная, перестает выполняться, данная переменная прекращает свое существование. Чтобы обеспечить доступность созданного экземпляра VirtualPet в классе после выполнения конструктора VirtualZoo, внесем изменения в этот класс. Вместо того чтобы присваивать объект VirtualPet локальной переменной, присвоим этот объект переменной экземпляра pet. Она будет закрытой, поэтому обращаться к ней можно только из кода класса VirtualZoo. Ниже представлен код, отражающий описанные изменения:

package zoo { public class VirtualZoo { private var pet;

public function VirtualZoo ( ) { this. pet = new VirtualPet(«Stan»);

}

}

}

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

Методы экземпляра

Метод экземпляра — это отдельный набор инструкций, выполняющих определенную задачу, связанную с данным объектом. По сути, методы экземпляра описывают действия, которые может выполнять тот или иной объект. Например, в предопределенном классе Sound (экземпляры которого представляют звуки в программе) описан метод экземпляра с именем play, который позволяет начать воспроизведение звука. Аналогичным образом в предопределенном классе TextField (экземпляры которого представляют текст на экране) описан метод с именем setSelection, позволяющий изменять количество выделенных символов в текстовом поле.

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

Для создания метода экземпляра используется описание функции внутри блока класса, как показано в следующем обобщенном коде:

class НекийКласс { function идентификатор ( ) {

}

}

В данном коде ключевое слово function обозначает начало описания метода экземпляра. Затем указывается имя метода экземпляра, которое может являться любым допустимым идентификатором (как уже упоминалось, имена идентификаторов не могут содержать пробелы или тире, а также не должны начинаться с цифры). За именем метода следует пара круглых скобок, содержащих список параметров метода, которые будут рассмотрены позднее. Фигурные скобки { и }, следующие за списком параметров, являются оператором блока. Оператор блока метода экземпляра называется телом метода. Оно содержит директивы, используемые для выполнения определенной задачи.

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

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

объект. имяМетода( )

В этом коде имяМетода — это имя метода, код которого должен быть выполнен, а объ — ект — ссылка на определенный экземпляр, который будет использоваться для выполнения задачи, представленной указанным методом. Использование выражения вызова для выполнения кода, описанного в теле метода экземпляра, называется вызовом метода объекта (или вызовом метода через объект). Кроме того, применяется термин «активизация», обозначающий вызов.

^_

При упоминании имени определенного метода в большинстве документации используется оператор круглых скобок (). Например, в обычной документации чаще пишут setSelection(), а не просто setSelection. Использование оператора скобок помогает различать в тексте имена методов и переменных.

Теперь реализуем представленные концепции в нашей программе создания виртуального зоопарка.

Чтобы наделить наших животных способностью питаться, добавим новую переменную экземпляра и новый метод экземпляра в класс VirtualPet. Новая переменная экземпляра — currentCalories — будет отслеживать количество пищи, съеденной каждым животным, в виде числового значения. В новом методе экземпляра eat ( ) будет реализована концепция принятия пищи путем добавления 100 калорий к текущему значению переменной экземпляра currentCalories. В конечном счете метод eat ( ) будет вызываться в ответ на действие пользователя — кормление животного.

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

Следующий код демонстрирует описание переменной currentCalories. Для исключения возможности влияния внешнего кода на количество калорий, которым обладает каждый экземпляр VirtualPet, переменная currentCalories описана с использованием модификатора private. Обратите внимание, что каждому новому экземпляру VirtualPet изначально присваивается 1000 калорий.

package zoo { internal class VirtualPet { internal var petName; private var currentCalories = 1000;

public function VirtualPet (name) { this. petName = name;

}

}

}

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

package zoo { internal class VirtualPet { internal var petName; private var currentCalories = 1000;

public function VirtualPet (name) { this. petName = name;

}

function eat ( ) { }

}

}

Хотя тело метода eat ( ) пока не содержит никаких инструкций, подобного описания вполне достаточно, чтобы вызвать метод еа t ( ) для объекта Virtual Ре t, как показано в следующей обновленной версии класса VirtualZoo:

package zoo { public class VirtualZoo { private var pet;

public function VirtualZoo ( ) { this. pet = new VirtualPet(«Stan»);

// Вызов метода eat( ) для объекта VirtualPet, ссылка на который // хранится в переменной pet this. pet. eat( );

}

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

В теле метода экземпляра объект, через который был вызван данный метод, называется текущим объектом. Для обращения к текущему объекту используется ключевое слово this. Обратите внимание, что понятие «текущий объект» может применяться как к объекту, создаваемому в методе-конструкторе, так и к объекту, через который был вызван метод экземпляра.

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

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

НекаяПеременная = некаяПеременная + числовоеЗначение

В случае с методом eat ( ) к значению переменной currentCalories текущего объекта (this) мы собираемся добавить 100. В результате получаем следующий код:

this. currentCalories = this. currentCalories + 100;

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

this. currentCalories += 100;

Код класса VirtualPet теперь выглядит следующим образом:

package zoo { internal class VirtualPet { internal var petName; private var currentCalories = 1000;

public function VirtualPet (name) { this. petName = name;

}

function eat ( ) { this. currentCalories += 100;

}

}

}

Начиная с текущего момента, при каждом вызове метода eat ( ) экземпляра VirtualPet значение переменной currentCalories данного экземпляра будет увеличиваться на 100. Например, следующий код, взятый из конструктора класса VirtualZoo, увеличивает значение переменной currentCalories экземпляра VirtualPet, ссылка на который хранится в переменной pet, до 1100 (поскольку

всем экземплярам VirtualPet изначально присваивается значение 1000 калорий).

this. pet = new VirtualPet(«Stan»); this. pet. eat( );

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

Модификаторы управления доступом для методов экземпляра

Для описаний методов экземпляра применяются те же модификаторы управления доступом, что и для переменных экземпляра: public, internal, protected и private. Доступ к методу экземпляра, объявленному с использованием модификатора public, может быть осуществлен как внешними командами по отношению к пакету, в котором метод создан, так и внутренними. Метод экземпляра, объявленный с использованием модификатора internal, доступен только для внутренних команд пакета, в котором он описан. Метод экземпляра, объявленный с использованием модификатора protected, может быть доступен только для кода класса, содержащего описание этого метода, или для кода потомков этого класса (мы еще не рассматривали наследование, поэтому, если вы незнакомы с объектно-ориентированным программированием, не обращайте внимания на этот модификатор). Метод экземпляра, объявленный с использованием модификатора private, может быть доступен только для кода класса, содержащего описание этого метода. В ситуации, когда при описании метода ни один из модификаторов не был указан, применяется модификатор internal (доступ внутри пакета).



Полезные ссылки
Случайные записи
  • 14.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.73
  • 22.03.2011">Руководство по actionscript. часть 2, стр. 019
  • 27.08.2010">Атрибуты .
  • 19.02.2012">Кто же такой верстальщик?
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 062
  • 13.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.88
  • 11.03.2011">Руководство по actionscript. часть 4, стр. 015
  • 14.03.2010">Логотипы. Где их искать?
  • 04.03.2011">Руководство по actionscript. часть 5, стр. 031
  • 18.03.2011">Руководство по actionscript. часть 2, стр. 117
  • 01.02.2013">Частные уроки вождения
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.70
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.89
  • 18.02.2011">Вырезание объекта с помощью фильтра в Photoshop
  • 09.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.142
Опрос

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

View Results

Loading ... Loading ...