Статьи

Javascript и ActionScript Converse: Введение в ExternalInterface

ActionScript и Javascript. Оба эти языка великолепны сами по себе, но задумывались ли вы когда-нибудь, что вы могли бы сделать, если бы они могли разговаривать друг с другом? Ну, тебе повезло! Вот где класс ExternalInterface входит в картину. Следуй за мной, пока я учу тебя основам.

Фото Дэйва Спеллмана .




В настоящее время класс ExternalInterface доступен в следующих браузерах:

  • Интернет Exlplorer 5.0+
  • Netscape 8.0+
  • Mozilla 1.7.5+
  • Firefox 1.0+
  • Safari 1.3+

Класс ExternalInterface позволяет вам:

  • Вызовите любую функцию Javascript из ActionScript.
  • Вызовите любую функцию ActionScript из Javascript.
  • Передавайте аргументы и параметры между ними.
  • Получить возвращаемое значение из функции Javascript.
  • Вернуть значение в функцию Javascript.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
        <title>ExternalInterface Test 1</title>
    </head>
 
    <body>
        <div id=»testArea»>
            <form name=»myForm»>
                <label for=»output»>Text from Flash</label>
                <input type=»text» id=»output» name=»output» value=»» />
            </form>
        </div>
    </body>
</html>

Чтобы легко ссылаться на SWF в нашем HTML, мы собираемся создать функцию Javascript, чтобы мы могли ссылаться на SWF в нашем коде. Для этого поместите этот скрипт между тегами «head».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<script type=»text/javascript»>
    function flashMovie(movieName)
    {
        if(window.document[movieName])
        {
            return window.document[movieName];
        }
        else
        {
            return document.getElementById(movieName);
        }
         
    }
</script>

Эта функция вернет SWF, переданный в качестве параметра функции flashMovie (). Например, «flashMovie (‘testMovie’);» вернет SWF с идентификатором «testMovie».

Теперь мы создадим функцию Javascript, которая принимает значение из ActionScript. Поместите это в наш уже созданный скрипт
теги.

1
2
3
4
function sendToJS(value)
{
    document.forms[«myForm»].output.value = value;
}

Это будет принимать любое значение, полученное нами из ActionScript, и помещать его в наше текстовое поле с идентификатором «output».

Давайте откроем Flash и начнем работать над ActionScript. Создайте новый файл ActionScript 3.0 и создайте новый класс документов с именем «EIFace1».

Создайте новый файл ActionScript 3.0.
Создать класс документа EIFace

Я буду использовать FDT для написания EIFace.as, но вы можете использовать любой редактор ActionScript, с которым вам удобно. Мы начнем с создания стандартной оболочки класса документов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package
{
    import flash.display.Sprite;
    /**
     * @author kreativeKING
     */
    public class EIFace1 extends Sprite
    {
        public function EIFace1()
        {
             
        }
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
field1 = new TextField();
field1.type = TextFieldType.INPUT;
field1.width = 300;
field1.height = 20;
field1.border = true;
field1.borderColor = 0x565656;
field1.background = true;
field1.backgroundColor = 0x121212;
field1.defaultTextFormat = new TextFormat(«Arial», 14, 0xEFEFEF);
field1.x = stage.stageWidth * .5 — field1.width *.5;
field1.y = stage.stageHeight * .5- field1.height *.5;
stage.addChild(field1);

Создать кнопку для нажатия. Я не фанат использования компонентов, поэтому буду создавать кнопки с нуля, используя Flash IDE. Вы можете просто создать коробку или использовать компонент SimpleButton; Я позволю вам использовать эти творческие соки. Если вам не нужна дополнительная помощь в создании кнопки, вы можете перейти к шагу 11.

Начните с создания прямоугольника с помощью инструмента Rectangle Primitive. Я не буду приводить конкретные значения, просто почувствуйте, как вам нравится.

Создать квадрат.

Преобразуйте прямоугольник в мувиклип.

Преобразовать в символ.

Создайте новый слой внутри мувиклипа и поместите текст «Отправить в JS».

Создать текст.

Зайдите в свою библиотеку, щелкните правой кнопкой мыши по кнопке и экспортируйте для ActionScript.

Экспорт для ActionScript.

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

1
2
3
4
5
button1 = new SendButton();
button1.x = stage.stageWidth * .5 — button1.width *.5;
button1.y = field1.y + 30;
 
stage.addChild(button1);

Вот как должна выглядеть ваша HTML-страница.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
        <title>ExternalInterface Test 1</title>
        <script type=»text/javascript»>
            function flashMovie(movieName)
            {
                if(window.document[movieName])
                {
                    return window.document[movieName];
                }
                else
                {
                    return document.getElementById(movieName);
                }
                 
            }
             
            function fromAS(value)
            {
                document.forms[«myForm»].output.value = value;
            }
        </script>
    </head>
 
    <body>
        <div id=»testArea»>
            <form name=»myForm»>
                <label for=»output»>Text from Flash</label>
                <input type=»text» id=»output» name=»output» value=»» />
            </form>
        </div>
    </body>
</html>

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    /**
     * @author kreativeKING
     */
    public class EIFace1 extends Sprite
    {
        private var field1 : TextField;
        private var button1 : MovieClip;
 
        public function EIFace1()
        {
            field1 = new TextField();
            field1.type = TextFieldType.INPUT;
            field1.width = 300;
            field1.height = 20;
            field1.border = true;
            field1.borderColor = 0x565656;
            field1.background = true;
            field1.backgroundColor = 0x121212;
            field1.defaultTextFormat = new TextFormat(«Arial», 14, 0xEFEFEF);
            field1.x = stage.stageWidth * .5 — field1.width *.5;
            field1.y = stage.stageHeight * .5- field1.height *.5;
             
            stage.addChild(field1);
             
            button1 = new SendButton();
            button1.x = stage.stageWidth * .5 — button1.width *.5;
            button1.y = field1.y + 30;
         
            stage.addChild(button1);
        }
    }
}

Теперь нам нужно создать функцию, которая отправляет данные из Flash в Javascript. Это будет простая функция, которая отправляет
строка.

1
2
3
4
5
6
7
8
9
button1.addEventListener(MouseEvent.CLICK, sendToJS);
 
private function sendToJS(e : MouseEvent) : void
{
    if(ExternalInterface.available)
    {
        ExternalInterface.call(«fromAS», field1.text);
    }
}

Сначала мы добавляем прослушиватель событий к нашей кнопке внутри конструктора классов документов. Затем мы создаем наш слушатель. Свойство ExternalInterface.available проверяет, может ли наш браузер использовать класс ExternalInterface. Это не обязательно использовать, поскольку мы знаем, что наш браузер может его поддерживать, но это хорошая практика для разработки для Интернета, и мы никогда не уверены, будет ли браузер клиента совместимым.

Функция ExternalInterface.call () — это то, что мы используем для вызова нашей функции Javascript. Первый параметр — это имя функции Javascript, которую мы хотим вызвать. Это имя нашей функции в Javascript в виде строки. Второй параметр — это значение, которое мы хотим передать функции Javascript. В этом случае мы передаем значение нашего текстового поля.

Примечание. Вы можете передать столько параметров, сколько хотите, но первым параметром должно быть имя функции Javascript.

Прежде чем мы сможем протестировать, мы должны сначала встроить наш SWF в HTML. Я должен подчеркнуть, что лучше всего использовать SWFObject, а не метод по умолчанию, который Flash использует для встраивания SWF-файлов. Давайте опубликуем наш SWF, настроим SWFObject и вставим наш файл.

Опубликуйте SWF.

Вот код для встраивания SWFObject, который входит в заголовок HTML-файла:

01
02
03
04
05
06
07
08
09
10
<script type=»text/javascript» src=»http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js»></script>
<script type=»text/javascript»>
    var flashvars = {};
    var params = {};
    params.allowscriptaccess = «always»;
    params.allownetworking = «all»;
    var attributes = {};
    attributes.id = «EIFace»;
    swfobject.embedSWF(«EIFace.swf», «flashDiv», «350», «200», «9.0.0», false, flashvars, params, attributes);
</script>

Также важно, чтобы вы указали идентификатор SWF. Это важно с использованием ExternalInterface и для нас, чтобы нацелиться на него, используя функцию Javascript, которую мы создали ранее. Давайте создадим наш div, в котором будет размещен SWF-файл.

1
2
3
<div id=»flashDiv»>
    <p>This will get replaced with a SWF.
</div>

Вот класс документов и HTML-файл до этого момента:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package
{
    import flash.external.ExternalInterface;
    import flash.events.MouseEvent;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    /**
     * @author kreativeKING
     */
    public class EIFace1 extends Sprite
    {
        private var field1 : TextField;
        private var button1 : MovieClip;
 
        public function EIFace1()
        {
            field1 = new TextField();
            field1.type = TextFieldType.INPUT;
            field1.width = 300;
            field1.height = 20;
            field1.border = true;
            field1.borderColor = 0x565656;
            field1.background = true;
            field1.backgroundColor = 0x121212;
            field1.defaultTextFormat = new TextFormat(«Arial», 14, 0xEFEFEF);
            field1.x = stage.stageWidth * .5 — field1.width *.5;
            field1.y = stage.stageHeight * .5- field1.height *.5;
             
            stage.addChild(field1);
             
            button1 = new SendButton();
            button1.x = stage.stageWidth * .5 — button1.width *.5;
            button1.y = field1.y + 30;
         
            stage.addChild(button1);
             
            button1.addEventListener(MouseEvent.CLICK, sendToJS);
        }
         
        private function sendToJS(e : MouseEvent) : void
        {
            if(ExternalInterface.available)
            {
                ExternalInterface.call(«fromAS», field1.text);
            }
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
        <title>ExternalInterface Test 1</title>
        <script type=»text/javascript» src=»http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js»></script>
        <script type=»text/javascript»>
            var flashvars = {};
            var params = {};
            params.allowscriptaccess = «always»;
            params.allownetworking = «all»;
            var attributes = {};
            attributes.id = «EIFace»;
            swfobject.embedSWF(«EIFace.swf», «flashDiv», «350», «200», «9.0.0», false, flashvars, params, attributes);
        </script>
        <script type=»text/javascript»>
            function flashMovie(movieName)
            {
                if(window.document[movieName])
                {
                    return window.document[movieName];
                }
                else
                {
                    return document.getElementById(movieName);
                }
                 
            }
                             
            function fromAS(value)
            {
                document.forms[«myForm»].output.value = value;
            }
        </script>
    </head>
 
    <body>
        <div id=»flashDiv»>
            <p>This will get replaced with a SWF.
        </div>
        <div id=»testArea»>
            <form name=»myForm»>
            <label for=»output»>Text from Flash</label>
                <input type=»text» id=»output» name=»output» value=»» />
            </form>
        </div>
    </body>
</html>

Теперь откройте свою HTML-оболочку и протестируйте ее. Вы увидите, что значение текстового поля во flash становится значением текстового поля в нашем HTML. На первый взгляд, код этого довольно прост и понятен. Теперь давайте попробуем отправить некоторую информацию из Javascript в ActionScript.

Мы собираемся создать дополнительные поля для отправки информации из Javascript в ActionScript.

1
2
3
<label for=»input»>Send Text To Flash</label>
<input type=»text» id=»input» name=»input» value=»» />
<input type=»button» value=»SendToFlash» onClick=»sendToFlash(myForm.input.value);»
01
02
03
04
05
06
07
08
09
10
11
12
13
field2 = new TextField();
field2.type = TextFieldType.DYNAMIC;
field2.width = 300;
field2.height = 20;
field2.border = true;
field2.borderColor = 0x565656;
field2.background = true;
field2.backgroundColor = 0xEFEFEF;
field2.defaultTextFormat = new TextFormat(«Arial», 14, 0x121212);
field2.x = stage.stageWidth * .5 — field2.width *.5;
field2.y = field1.y — 50;
 
stage.addChild(field2);

Нам нужно создать функцию, которая отправляет значение из нашего HTML во Flash. Это похоже на функцию, которую мы создали для отправки значений из ActionScript в Javascript.

1
2
3
4
function sendToFlash(value)
{
    flashMovie(«EIFace»).sendToFlash(value);
}

Мы используем функцию, которую мы создали ранее, чтобы ссылаться на встроенный SWF. Теперь мы должны зайти в наш класс документов и настроить Flash для получения значений из Javascript и создать новую функцию, которую будет вызывать Javascript.

Чтобы зарегистрировать функции Javascript, нам нужно добавить обратные вызовы, чтобы Flash знал, что мы пытаемся отправить, когда мы вызываем функцию ActionScript. Давайте наконец начнем вызывать некоторый ActionScript.

1
2
3
4
5
6
7
private function addCallbacks() : void
{
    if(ExternalInterface.available)
    {
        ExternalInterface.addCallback(«sendToFlash», fromJS);
    }
}

Функция ExternalInterface.addCallback () регистрирует функцию в ActionScript, вызываемую Javascript. Первый параметр — это имя функции, по которому Javascript будет знать функцию. Второй параметр — это фактическая функция.

Проще говоря, это означает, что в нашем Javascript мы бы вызвали sendToFlash (), и это вызвало бы функцию fromJS () в ActionScript.

Теперь мы собираемся создать функцию fromJS (). Это очень простая функция, которая присваивает значение, переданное ей, текстовому полю.

1
2
3
4
private function fromJS(value:String) : void
{
    field2.text = value;
}

Время для еще одного теста и посмотрим, что мы придумаем. Вот как теперь выглядят Document Class и HTML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package
{
    import flash.external.ExternalInterface;
    import flash.events.MouseEvent;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    /**
     * @author kreativeKING
     */
    public class EIFace1 extends Sprite
    {
        private var field1 : TextField;
        private var button1 : MovieClip;
        private var field2 : TextField;
 
        public function EIFace1()
        {
            field1 = new TextField();
            field1.type = TextFieldType.INPUT;
            field1.width = 300;
            field1.height = 20;
            field1.border = true;
            field1.borderColor = 0x565656;
            field1.background = true;
            field1.backgroundColor = 0x121212;
            field1.defaultTextFormat = new TextFormat(«Arial», 14, 0xEFEFEF);
            field1.x = stage.stageWidth * .5 — field1.width *.5;
            field1.y = stage.stageHeight * .5- field1.height *.5;
             
            stage.addChild(field1);
             
            field2 = new TextField();
            field2.type = TextFieldType.DYNAMIC;
            field2.width = 300;
            field2.height = 20;
            field2.border = true;
            field2.borderColor = 0x565656;
            field2.background = true;
            field2.backgroundColor = 0xEFEFEF;
            field2.defaultTextFormat = new TextFormat(«Arial», 14, 0x121212);
            field2.x = stage.stageWidth * .5 — field2.width *.5;
            field2.y = field1.y — 50;
             
            stage.addChild(field2);
             
            button1 = new SendButton();
            button1.x = stage.stageWidth * .5 — button1.width *.5;
            button1.y = field1.y + 30;
         
            stage.addChild(button1);
             
            button1.addEventListener(MouseEvent.CLICK, sendToJS);
            addCallbacks();
        }
         
        private function addCallbacks() : void
        {
            if(ExternalInterface.available)
            {
                ExternalInterface.addCallback(«sendToFlash», fromJS);
            }
        }
         
        private function fromJS(value:String) : void
        {
            field2.text = value;
        }
 
        private function sendToJS(e : MouseEvent) : void
        {
            if(ExternalInterface.available)
            {
                ExternalInterface.call(«fromAS», field1.text);
            }
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
        <title>ExternalInterface Test 1</title>
        <script type=»text/javascript» src=»http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js»></script>
        <script type=»text/javascript»>
            var flashvars = {};
            var params = {};
            params.allowscriptaccess = «always»;
            params.allownetworking = «all»;
            var attributes = {};
            attributes.id = «EIFace»;
            swfobject.embedSWF(«EIFace.swf», «flashDiv», «350», «200», «9.0.0», false, flashvars, params, attributes);
        </script>
        <script type=»text/javascript»>
            function flashMovie(movieName)
            {
                if(window.document[movieName])
                {
                    return window.document[movieName];
                }
                else
                {
                    return document.getElementById(movieName);
                }
                 
            }
                         
            function fromAS(value)
            {
                document.forms[«myForm»].output.value = value;
            }
             
            function sendToFlash(value)
            {
                flashMovie(«EIFace»).sendToFlash(value);
            }
        </script>
    </head>
 
    <body>
        <div id=»flashDiv»>
            <p>This will get replaced with a SWF.
        </div>
        <div id=»testArea»>
            <form name=»myForm»>
            <label for=»input»>Send Text To Flash</label>
            <input type=»text» id=»input» name=»input» value=»» />
            <input type=»button» value=»SendToFlash» onClick=»sendToFlash(myForm.input.value);»
            <br />
            <br />
            <label for=»output»>Text from Flash</label>
                <input type=»text» id=»output» name=»output» value=»» />
            </form>
        </div>
    </body>
</html>

Как видите, размещение текста в нашем новейшем поле и нажатие кнопки send отправляет значение в текстовое поле Flash. Использование класса ExternalInterface очень просто и часто может пригодиться при создании API и приложений, которыми можно манипулировать вне Flash Movie. Например, это может быть реализовано в API проигрывателя видео для создания и управления видео с помощью Javascript.

Для большинства людей сейчас никто не использует классический Javascript; jQuery — это волна будущего. Вот пример использования jQuery вместо классического Javascript.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script type=»text/javascript»>
    $(
        function()
        {
            $(‘#sendToFlash’).click(function()
            {
                if($(‘#EIFace’)[0])
                {
                    $(‘#EIFace’)[0].sendToFlash($(‘#input’).val());
                }
                else
                {
                    $(‘#EIFace’).sendToFlash($(‘#input’).val());
                }
            });
        }
    );
     
    function fromAS(value)
    {
        $(‘#output’).val(value);
    }
</script>

Вот новый и обновленный HTML для использования с jQuery:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
        <title>ExternalInterface Test 1</title>
        <script type=»text/javascript» src=»http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js»></script>
        <script type=»text/javascript» src=»http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js»></script>
        <script type=»text/javascript»>
            var flashvars = {};
            var params = {};
            params.allowscriptaccess = «always»;
            params.allownetworking = «all»;
            var attributes = {};
            attributes.id = «EIFace»;
            swfobject.embedSWF(«EIFace.swf», «flashDiv», «350», «200», «9.0.0», false, flashvars, params, attributes);
        </script>
        <script type=»text/javascript»>
            $(
                function()
                {
                    $(‘#sendToFlash’).click(function()
                    {
                        if($(‘#EIFace’)[0])
                        {
                            $(‘#EIFace’)[0].sendToFlash($(‘#input’).val());
                        }
                        else
                        {
                            $(‘#EIFace’).sendToFlash($(‘#input’).val());
                        }
                    });
                }
            );
             
            function fromAS(value)
            {
                $(‘#output’).val(value);
            }
        </script>
    </head>
 
    <body>
        <div id=»flashDiv»>
            <p>This will get replaced with a SWF.
        </div>
        <div id=»testArea»>
            <form name=»myForm»>
            <label for=»input»>Send Text To Flash</label>
            <input type=»text» id=»input» name=»input» value=»» />
            <input type=»button» id=»sendToFlash» value=»SendToFlash» />
            <br />
            <br />
            <label for=»output»>Text from Flash</label>
                <input type=»text» id=»output» name=»output» value=»» />
            </form>
        </div>
    </body>
</html>

Надеюсь, теперь вы лучше разбираетесь в использовании класса ExternalInterface. Если у вас есть какие-либо вопросы или идеи о том, что еще вы хотели бы узнать, просто оставьте комментарий или напишите мне, и я посмотрю, что я могу сделать. Я надеюсь, что вы изучили концепции и начали использовать их в своих собственных проектах. Спасибо за прочтение!

kreativeKING