Евгений Колесников 1 ماه پیش
والد
کامیت
cbfec4da12

BIN
.DS_Store


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 93723 - 0
articles/cryptonomicon/app.css


+ 235 - 0
articles/cryptonomicon/index.html

@@ -0,0 +1,235 @@
+<html>
+  <head>
+    <link rel="stylesheet" href="app.css"></link>
+  </head>
+<body>
+<div class="container mx-auto flex flex-col items-center bg-gray-100 p-4">
+  <!--div class="fixed w-100 h-100 opacity-80 bg-purple-800 inset-0 z-50 flex items-center justify-center">
+    <svg class="animate-spin -ml-1 mr-3 h-12 w-12 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
+      <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
+      <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
+    </svg>
+  </div-->
+  <div class="container">
+    <section>
+      <div class="flex">
+        <div class="max-w-xs">
+          <label for="wallet" class="block text-sm font-medium text-gray-700"
+            >Тикер</label
+          >
+          <div class="mt-1 relative rounded-md shadow-md">
+            <input
+              type="text"
+              name="wallet"
+              id="wallet"
+              class="block w-full pr-10 border-gray-300 text-gray-900 focus:outline-none focus:ring-gray-500 focus:border-gray-500 sm:text-sm rounded-md"
+              placeholder="Например DOGE"
+            />
+          </div>
+          <div class="flex bg-white shadow-md p-1 rounded-md shadow-md flex-wrap">
+            <span class="inline-flex items-center px-2 m-1 rounded-md text-xs font-medium bg-gray-300 text-gray-800 cursor-pointer">
+              BTC
+            </span>
+            <span class="inline-flex items-center px-2 m-1 rounded-md text-xs font-medium bg-gray-300 text-gray-800 cursor-pointer">
+              DOGE
+            </span>
+            <span class="inline-flex items-center px-2 m-1 rounded-md text-xs font-medium bg-gray-300 text-gray-800 cursor-pointer">
+              BCH
+            </span>
+            <span class="inline-flex items-center px-2 m-1 rounded-md text-xs font-medium bg-gray-300 text-gray-800 cursor-pointer">
+              CHD
+            </span>
+          </div>
+          <div class="text-sm text-red-600">Такой тикер уже добавлен</div>
+        </div>
+      </div>
+      <button
+        type="button"
+        class="my-4 inline-flex items-center py-2 px-4 border border-transparent shadow-sm text-sm leading-4 font-medium rounded-full text-white bg-gray-600 hover:bg-gray-700 transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
+      >
+        <!-- Heroicon name: solid/mail -->
+        <svg
+          class="-ml-0.5 mr-2 h-6 w-6"
+          xmlns="http://www.w3.org/2000/svg"
+          width="30"
+          height="30"
+          viewBox="0 0 24 24"
+          fill="#ffffff"
+        >
+          <path
+            d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"
+          ></path>
+        </svg>
+        Добавить
+      </button>
+    </section>
+
+      <hr class="w-full border-t border-gray-600 my-4" />
+      <dl class="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
+        <div
+          class="bg-white overflow-hidden shadow rounded-lg border-purple-800 border-solid cursor-pointer"
+        >
+          <div class="px-4 py-5 sm:p-6 text-center">
+            <dt class="text-sm font-medium text-gray-500 truncate">
+              WTF - USD
+            </dt>
+            <dd class="mt-1 text-3xl font-semibold text-gray-900">
+              1.11
+            </dd>
+          </div>
+          <div class="w-full border-t border-gray-200"></div>
+          <button
+            class="flex items-center justify-center font-medium w-full bg-gray-100 px-4 py-4 sm:px-6 text-md text-gray-500 hover:text-gray-600 hover:bg-gray-200 hover:opacity-20 transition-all focus:outline-none"
+          >
+            <svg
+              class="h-5 w-5"
+              xmlns="http://www.w3.org/2000/svg"
+              viewBox="0 0 20 20"
+              fill="#718096"
+              aria-hidden="true"
+            >
+              <path
+                fill-rule="evenodd"
+                d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
+                clip-rule="evenodd"
+              ></path></svg>Удалить
+          </button>
+        </div>
+        <div
+          class="bg-white overflow-hidden shadow rounded-lg border-purple-800 border-solid border-4 cursor-pointer"
+        >
+          <div class="px-4 py-5 sm:p-6 text-center">
+            <dt class="text-sm font-medium text-gray-500 truncate">
+              VUE - RUB
+            </dt>
+            <dd class="mt-1 text-3xl font-semibold text-gray-900">
+              80000.00
+            </dd>
+          </div>
+          <div class="w-full border-t border-gray-200"></div>
+          <button
+            class="flex items-center justify-center font-medium w-full bg-gray-100 px-4 py-4 sm:px-6 text-md text-gray-500 hover:text-gray-600 hover:bg-gray-200 hover:opacity-20 transition-all focus:outline-none"
+          >
+            <svg
+              class="h-5 w-5"
+              xmlns="http://www.w3.org/2000/svg"
+              viewBox="0 0 20 20"
+              fill="#718096"
+              aria-hidden="true"
+            >
+              <path
+                fill-rule="evenodd"
+                d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
+                clip-rule="evenodd"
+              ></path></svg>Удалить
+          </button>
+        </div>
+        <div
+          class="bg-white overflow-hidden shadow rounded-lg border-purple-800 border-solid cursor-pointer"
+        >
+          <div class="px-4 py-5 sm:p-6 text-center">
+            <dt class="text-sm font-medium text-gray-500 truncate">
+              BTC - USD
+            </dt>
+            <dd class="mt-1 text-3xl font-semibold text-gray-900">
+              99999.99
+            </dd>
+          </div>
+          <div class="w-full border-t border-gray-200"></div>
+          <button
+            class="flex items-center justify-center font-medium w-full bg-gray-100 px-4 py-4 sm:px-6 text-md text-gray-500 hover:text-gray-600 hover:bg-gray-200 hover:opacity-20 transition-all focus:outline-none"
+          >
+            <svg
+              class="h-5 w-5"
+              xmlns="http://www.w3.org/2000/svg"
+              viewBox="0 0 20 20"
+              fill="#718096"
+              aria-hidden="true"
+            >
+              <path
+                fill-rule="evenodd"
+                d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
+                clip-rule="evenodd"
+              ></path></svg>Удалить
+          </button>
+        </div>
+        <div
+          class="bg-white overflow-hidden shadow rounded-lg border-purple-800 border-solid cursor-pointer"
+        >
+          <div class="px-4 py-5 sm:p-6 text-center">
+            <dt class="text-sm font-medium text-gray-500 truncate">
+              DOGE - USD
+            </dt>
+            <dd class="mt-1 text-3xl font-semibold text-gray-900">
+              0.0014
+            </dd>
+          </div>
+          <div class="w-full border-t border-gray-200"></div>
+          <button
+            class="flex items-center justify-center font-medium w-full bg-gray-100 px-4 py-4 sm:px-6 text-md text-gray-500 hover:text-gray-600 hover:bg-gray-200 hover:opacity-20 transition-all focus:outline-none"
+          >
+            <svg
+              class="h-5 w-5"
+              xmlns="http://www.w3.org/2000/svg"
+              viewBox="0 0 20 20"
+              fill="#718096"
+              aria-hidden="true"
+            >
+              <path
+                fill-rule="evenodd"
+                d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
+                clip-rule="evenodd"
+              ></path></svg>Удалить
+          </button>
+        </div>
+      </dl>
+      <hr class="w-full border-t border-gray-600 my-4" />
+    <section class="relative">
+      <h3 class="text-lg leading-6 font-medium text-gray-900 my-8">
+        VUE - USD
+      </h3>
+      <div class="flex items-end border-gray-600 border-b border-l h-64">
+        <div
+          class="bg-purple-800 border w-10 h-24"
+        ></div>
+        <div
+          class="bg-purple-800 border w-10 h-32"
+        ></div>
+        <div
+          class="bg-purple-800 border w-10 h-48"
+        ></div>
+        <div
+          class="bg-purple-800 border w-10 h-16"
+        ></div>
+      </div>
+      <button
+        type="button"
+        class="absolute top-0 right-0"
+      >
+        <svg
+          xmlns="http://www.w3.org/2000/svg"
+          xmlns:xlink="http://www.w3.org/1999/xlink"
+          xmlns:svgjs="http://svgjs.com/svgjs"
+          version="1.1"
+          width="30"
+          height="30"
+          x="0"
+          y="0"
+          viewBox="0 0 511.76 511.76"
+          style="enable-background:new 0 0 512 512"
+          xml:space="preserve"
+        >
+          <g>
+            <path
+              d="M436.896,74.869c-99.84-99.819-262.208-99.819-362.048,0c-99.797,99.819-99.797,262.229,0,362.048    c49.92,49.899,115.477,74.837,181.035,74.837s131.093-24.939,181.013-74.837C536.715,337.099,536.715,174.688,436.896,74.869z     M361.461,331.317c8.341,8.341,8.341,21.824,0,30.165c-4.16,4.16-9.621,6.251-15.083,6.251c-5.461,0-10.923-2.091-15.083-6.251    l-75.413-75.435l-75.392,75.413c-4.181,4.16-9.643,6.251-15.083,6.251c-5.461,0-10.923-2.091-15.083-6.251    c-8.341-8.341-8.341-21.845,0-30.165l75.392-75.413l-75.413-75.413c-8.341-8.341-8.341-21.845,0-30.165    c8.32-8.341,21.824-8.341,30.165,0l75.413,75.413l75.413-75.413c8.341-8.341,21.824-8.341,30.165,0    c8.341,8.32,8.341,21.824,0,30.165l-75.413,75.413L361.461,331.317z"
+              fill="#718096"
+              data-original="#000000"
+            ></path>
+          </g>
+        </svg>
+      </button>
+    </section>
+  </div>
+</div>
+</body>
+</html>

BIN
articles/cryptonomicon/vue_01.jpg


BIN
articles/cryptonomicon/vue_02.jpg


+ 0 - 0
img/web_008.png → articles/cryptonomicon/web_008.png


+ 0 - 0
img/web_011.png → articles/cryptonomicon/web_011.png


+ 0 - 0
img/web_012.png → articles/cryptonomicon/web_012.png


+ 0 - 0
img/web_013.png → articles/cryptonomicon/web_013.png


BIN
articles/cryptonomicon/web_014.png


+ 49 - 43
articles/web_04.md

@@ -1,6 +1,6 @@
 [Назад](./web_03.md) | [К содержанию](../readme.md#введение-в-web-разработку) | [Дальше](./web_05.md)
 
-# Vue.js: концепции
+# Vue.js: концепции, криптономикон
 
 ## #8 Бизнес логика или детали реализации?
 
@@ -28,7 +28,7 @@
 
 ### Материалы к заданию
 
-1. [Исходный HTML/CSS для самостоятельного повторения](https://gitlab.com/vuejs-club/youtube-course/cryptonomicon-html)
+<!-- 1. [Исходный HTML/CSS для самостоятельного повторения](https://gitlab.com/vuejs-club/youtube-course/cryptonomicon-html) -->
 1. Материалы к изучению: под роликом на ютубе куча ссылок, но в принципе там раздел "Основы" от [Синтаксиса шаблонов](https://v3.ru.vuejs.org/ru/guide/template-syntax.html) до "Работы с формами"
 1. [API для получения ключа:](https://www.cryptocompare.com/)
 
@@ -75,27 +75,27 @@
 
 ### Добавление вёрстки и стилей
 
[материалах](#материалы-к-заданию) есть ссылка на файлы с вёрсткой. 
этом репозитории есть каталог с файлами html и css ([/articles/cryptonomicon](./cryptonomicon/)). Можно открыть в браузере файл `index.html`, чтобы понимать, как должен выглядеть готовый проект
 
-1. Скопируйте содержимое `<body>` из файла `index.htm` в ваш шаблон (внутрь тега `<template>` вместо комментария)
+![Оригинальная верстка](./cryptonomicon/vue_01.jpg)
 
-    Все сработало. Как видите все подключилось но выглядит как-то криво 
+1. Скопируйте содержимое тега `<body>` из файла `index.htm` в ваш шаблон (внутрь тега `<template>` вместо комментария)
+
+    После копирования шаблона проект должен выглядеть как-то так:
     
-    ![](../img/web_008.png)
+    ![Шаблон без стилей](./cryptonomicon/web_008.png)
     
+    Как видите все подключилось но выглядит криво.
+
     Очевидно нам нужны стили. Как можно подключить `css`? В рамках скринкаста стили добавлены прямо в файл `App.vue`, но мы сделаем более правильно: скопируйте файл `app.css` в каталог `src/assets` и в файле `main.js` раскомментируйте и поправьте строчку с импортом файла стилей
 
     ```js
     import './assets/app.css'
     ```
 
-    Почему-то в проекте на `vite` показывает крутилку на весь экран, удалите из вёрстки первый `<div>` с этим спиннером (у меня он закомментирован)
-
-    ![](../img/web_010.png)    
-
     Теперь всё выглядит "красиво"
 
-    ![](../img/web_009.png)
+    ![Шаблон со стилями](./cryptonomicon/vue_01.jpg)
 
 ### Начинаем работу с App.vue
 
@@ -107,11 +107,11 @@
 
 Ну что же давайте учиться это делать. Как вы помните **vue** декларативен. Что это означает? Это означает, что нам надо будет выучить язык описания компонентов, благо он не сложный. То есть у нас есть несколько заранее зарезервированных слов, с помощью которых мы будем объявлять те или иные особенности компонент.
 
->Дальше в скринкасте расписывается функция `data()`, которая возвращает реактивные данные, доступные в шаблоне. Но это устаревший синтаксис __Option API__ из **Vue2**, во **Vue3** стандартом является `Setup API`, причем имеющий два варианта написания: функция `setup()` и `script setup`. Мы будем использовать `<script setup>`.
+>Дальше в скринкасте расписывается функция `data()`, которая возвращает реактивные данные, доступные в шаблоне. Но это устаревший синтаксис __Option API__ из **Vue2**, во **Vue3** стандартом является `Setup API`, причем имеющий два варианта написания: функция `setup()` и `<script setup>`. Мы будем использовать `<script setup>`.
 
 Просто определим [реактивную](https://ru.vuejs.org/guide/essentials/reactivity-fundamentals.html) переменную:
 
-```vue
+```js
 <script setup>
 import { ref } from "vue"
 const ticker = ref('default')
@@ -124,9 +124,9 @@ const ticker = ref('default')
 
 `v-model` как раз говорит "свяжи мне в две стороны вот этот вот __input__ с данными (переменной _ticker_)"
 
-![](../img/web_011.png)
+![input с v-model](./cryptonomicon/web_011.png)
 
-![](../img/web_012.png)
+![верстка с default](./cryptonomicon/web_012.png)
 
 И вот у нас в поле ввода появилось значение `default`, но перед тем как что то делать я бы хотел убедиться что связь работает в обе стороны, т.е. когда правим поле ввода меняется и значение переменной.
 
@@ -136,15 +136,15 @@ const ticker = ref('default')
 
 Например:
 
-```vue
+```html
 <label 
-    for="wallet" 
-    class="block 
-        text-sm 
-        font-medium 
-        text-gray-700"
+  for="wallet" 
+  class="block 
+      text-sm 
+      font-medium 
+      text-gray-700"
 >
-    Тикер {{ ticker }}
+  Тикер {{ ticker }}
 </label>    
 ```
 
@@ -156,7 +156,7 @@ const ticker = ref('default')
 
 Как бы мы это делали в обычном java-скрипте? Мы нашли бы элемент на страничке через query-селектор, добавили слушатель на события клик и после этого сказали бы какую функцию вызывать.
 
-Во __VUE__ все работает похожим образом. Мы пишем `v-on:click="..."` (мы говорили что все атрибуты **VUE** начинаются с `v-`), дальше имя события клик. Мы здесь можем написать обычный java-скрипт код (например, `"ticker = 123"`). И при нажатии кнопку "добавить" в переменную `ticker` запишется значение `123` и верстка автоматически изменилась (поменялось содержимое поля ввода и метки).
+Во __VUE__ все работает похожим образом. Мы пишем `v-on:click="..."` (мы говорили что все атрибуты **VUE** начинаются с `v-`), дальше имя события (__click__). Мы здесь можем написать обычный java-скрипт код (например, `"ticker = 123"`). И при нажатии кнопку "добавить" в переменную `ticker` запишется значение `123` и верстка автоматически изменилась (поменялось содержимое поля ввода и метки).
 
 Но согласитесь писать код прямо в верстке как то странно, поэтому мы хотим чтобы код можно было писать рядом с вёрсткой (вспоминаем про **SFC**)
 
@@ -171,28 +171,34 @@ import { ref } from "vue"
 const ticker = ref('default')
 
 function add () {
-  alert('Я работаю!')
+  console.log('Я работаю!')
 }
 </script>
 ```
 
-Обратите внимание здесь можно будет потом передавать аргументы, то есть в 99% случаях надпись `add` и `add()` абсолютно одинаковы.
+Обратите внимание! В обработчик события можно будет потом передавать аргументы, то есть в 99% случаях надпись `add` и `add()` абсолютно одинаковы.
 
-Итак пробуем: выводится алерт
+>Я поменял alert на вывод в лог, чтобы сразу показать как работать с инструментами разработчика в браузере
+>
+>Кликните правой кнопкой в окне браузера и выберите пункт "Просмотреть код" (есть короткая клавиша __F12__)
+>
+>Затем в закладках выберите "Консоль":
+>
+>![devtool с логами](./cryptonomicon/vue_02.jpg)
 
-Хорошо, но нам же хочется в скрипте дотянуться до значения, введенного в input. Как же нам это делать?
+Хорошо, но нам же хочется в скрипте дотянуться до значения, введенного в `input`. Как же нам это делать?
 
 >...`this` используется только во **Vue2**, во **Vue3** используется ЗНАЧЕНИЕ (поле `value`) реактивной переменной
 
 ```js
 function add () {
-  alert(ticker.value)
+  consol.log(ticker.value)
 }
 ```
 
 Проверяем, действительно вывелось ровно то значение которое введено в `input`.
 
-Подождите, я хочу ещё, чтобы это событие срабатывало, когда я нажимаю кнопку `Enter` (дальше я пропустил полет мысли и привожу финальный результат: `v-on:keydown.enter` - при возникновении события нажатия клавиши `Enter` выполнить функцию `add`)
+Подождите, я хочу ещё, чтобы это событие срабатывало, когда я нажимаю кнопку `Enter` при вводе названия тикера (дальше я пропустил полет мысли и привожу финальный результат: `v-on:keydown.enter` - при возникновении события нажатия клавиши `Enter` выполнить функцию `add`)
 
 ```js
 <input
@@ -211,9 +217,9 @@ const tickers = ref([1, 2, 3, 4])
 
 #### [Отрисовка списков](https://ru.vuejs.org/guide/essentials/list.html)
 
-Как сказать **vue** "повтори какую-то вещь несколько раз"?
+Как сказать **VUE** "повтори какую-то вещь несколько раз"?
 
-Во-первых, что за вещь мне надо повторять? Нужно в верстке найти место, которое повторяется, удалить лишние повторы и использовать так называемую структурную директиву (директивами называются атрибуты которые обрабатываются **vue** опять же существенное упрощение но пока сойдет и так) `v-for`. У нас есть две ключевые структурные директивы мы потом поговорим почему они являются структурными но пока запомнить `v-for` и `v-if` они настолько суровы что даже друг с другом не дружат.
+Во-первых, что за вещь мне надо повторять? Нужно в верстке найти место, которое повторяется, удалить лишние повторы и использовать так называемую структурную директиву (директивами называются атрибуты которые обрабатываются **VUE** опять же существенное упрощение но пока сойдет и так) `v-for`. У нас есть две ключевые структурные директивы мы потом поговорим почему они являются структурными но пока запомнить `v-for` и `v-if` они настолько суровы что даже друг с другом не дружат.
 
 ```html
 <div
@@ -222,11 +228,9 @@ const tickers = ref([1, 2, 3, 4])
     ...
 ```
 
->Я много раз повторял, что название переменных должно быть самоочевидным и, по идее, переменная цикла должна называться `ticker`, но в этом случае она будет "перекрывать" одноименную переменную из скрипта. Нужно либо переименовать в скрипте переменную `tiker` в `tickerName` (мы не будем этого делать, чтобы не рассинхронизироваться со скринкастом), либо использовать переменную цикла `t` (для циклов и лямбда функций допускается использование однобуквенных переменных цикла)
-
 Этот код говорит "для всех tickers повтори пожалуйста вот этот блок". Дальше нам выдаст ошибку про `key`.
 
-Для циклов нужно использовать констукцию `v-bind:key="уникальное значение"`. В нашем случае мы можем использовать просто значение `t`, но есть синтаксис `v-for` c индексом:
+Для циклов нужно использовать констукцию `v-bind:key="уникальное значение"`. В нашем случае мы можем использовать просто значение `t`, но лучше использовать вариант синтаксиса `v-for` c индексом:
 
 ```html
 <div
@@ -243,11 +247,11 @@ const tickers = ref([1, 2, 3, 4])
         </dt>
 ```
 
-Давайте чуть-чуть доведем до ума, но перед этим сделаем маленький шаг назад дело в том что в мире **vue** огромное количество раз вы будете писать в `v-bind` и `v-on`.
+Давайте чуть-чуть доведем до ума, но перед этим сделаем маленький шаг назад дело в том что в мире **VUE** огромное количество раз вы будете писать в `v-bind` и `v-on`.
 
 Писать так очень многословно поэтому придумали так называемую короткую запись, когда вместо `v-on` мы пишем собаку `@`, а вместо `v-bind` просто ничего не пишут, оставляют только  `:`.
 
-Нам надо выводить будет явное имя валюты и значение соответственно наш массив нужно переопределить как то так:
+Нам надо будет выводить явное имя валюты и значение, соответственно наш массив нужно переопределить как то так:
 
 ```js
 const tickers = ref([
@@ -257,9 +261,9 @@ const tickers = ref([
 ])  
 ```
 
-![](../img/web_013.png)
+![строковый вывод объекта](./cryptonomicon/web_013.png)
 
-Видите, теперь он начал выводить переменную `t` которая содержит весь объект и радостно нарисовал строковое представление объекта. Нам надо вывести поля `name` и `price`:
+Видите, теперь он начал выводить переменную `t`, которая содержит весь объект и радостно нарисовал строковое представление объекта. Нам надо вывести поля `name` и `price`:
 
 ```js
 <dt class="text-sm font-medium text-gray-500 truncate">
@@ -272,7 +276,7 @@ const tickers = ref([
 
 #### Добавление элементов
 
-Давайте научимся для начала добавлять такие элементы плюс давайте приведем это всё в тот дизайн который был, а именно добавим `USD` в пару:
+Давайте научимся для начала добавлять такие элементы, плюс давайте приведем это всё в тот дизайн который был, а именно добавим `USD` в пару:
 
 ```js
 <dt class="text-sm font-medium text-gray-500 truncate">
@@ -292,7 +296,7 @@ function add () {
 }
 ```
 
->Не забываем, что обращение к значению реактивной переменной происходит через свойство `.value`
+>Не забываем, что обращение к значению реактивной переменной (в нашем случае массив _tickers_) происходит через свойство `.value`
 
 Хорошо теперь только нам осталось вместо имени подставить название нового тикера:
 
@@ -322,11 +326,11 @@ function add () {
 }
 ```
 
-Обратите внимание это фундаментальный акцент на том как вообще работает **vue**. Мы хотим и умеем работать с данными html декларативно (мы же теперь с вами знаем это слово). Описываем как к этим данным привязать переменные и никогда не меняем html напрямую 
+Обратите внимание это фундаментальный акцент на том как вообще работает **VUE**. Мы хотим и умеем работать с данными html декларативно (мы же теперь с вами знаем это слово). Описываем как к этим данным привязать переменные и никогда не меняем html напрямую 
 
 #### Удаление пар
 
-Хорошо давайте двигаться дальше - теперь мы хотим удалять валюты. Прекрасно давайте найдем эту кнопку удалить, повесим на нее событие __click__ и назовем `handleDelete`:
+Хорошо давайте двигаться дальше - теперь мы хотим удалять валюты. Прекрасно давайте найдем кнопку удалить, повесим на нее событие __click__ и назовем `handleDelete`:
 
 
 ```html
@@ -345,11 +349,13 @@ function handleDelete (tickerToRemove) {
 }
 ```
 
+>Метод записывает в массив _tickers_ фильтрованный массив, в котором возвращаются все элементы, кроме того который удаляем 
+
 #### v-if
 
 Удаление работает, только вот видите некрасивый вот эти две полосочки 
 
-![](../img/web_014.png)
+![две полоски](./cryptonomicon/web_014.png)
 
 Мы бы хотели, чтобы их не было, чтобы этот кусок вообще не отображался, когда у меня нет данных.
 

+ 39 - 3
articles/web_18.md

@@ -2,7 +2,43 @@
 
 # Карусель
 
->Будет использоваться в приложении "Управление коллекцией фильмов"
+## АПИ "Управление коллекцией фильмов"
+
+Для получения списка фильмов (и их изображений) можно использовать АПИ "Управление коллекцией фильмов"
+
+Для получения списка фильмов используйте метод:
+
+```rest
+GET https://cinema.kolei.ru/movies?filter=new
+```
+
+в ответ получите JSON-массив:
+
+```json
+[
+  {
+    "movieId": 1,
+    "name": "Дюна",
+    "description": "Атрейдесы прибывают на планету, где им никто не рад. Фантастический эпос Дени Вильнёва с шестью «Оскарами»",
+    "age": "12",
+    "images": [
+      "duna_wallpaper.jpg"
+    ],
+    "poster": "duna.webp",
+    "tags": [],
+    "category": "Фентези"
+  },
+  ...
+]
+```
+
+Для получения картинки используйте УРЛ `https://cinema.kolei.ru/up/images/<название картинки из поля poster>`, например:
+
+```rest
+GET https://cinema.kolei.ru/up/images/duna.webp
+```
+
+## Задание
 
 На примере карусели разберёмся, как подключать дополнительные js-библиотеки
 
@@ -16,9 +52,9 @@
     npm install swiper
     ```
 
-1. В компоненте в котором вы будете использовать карусель необходимо зарегистрировать компонент карусели
+1. В компоненте, в котором вы будете использовать карусель, необходимо зарегистрировать компонент карусели
 
-    ```vue
+    ```js
     <script setup>
     import { register } from 'swiper/element/bundle'
     register()

+ 310 - 126
cinema/package-lock.json

@@ -1,28 +1,42 @@
 {
   "name": "cinema",
   "version": "1.0.0",
-  "lockfileVersion": 1,
+  "lockfileVersion": 3,
   "requires": true,
-  "dependencies": {
-    "accepts": {
+  "packages": {
+    "": {
+      "name": "cinema",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "cors": "^2.8.5",
+        "express": "^4.18.2",
+        "express-fileupload": "^1.4.0",
+        "md5": "^2.3.0"
+      }
+    },
+    "node_modules/accepts": {
       "version": "1.3.8",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
       "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
-      "requires": {
+      "dependencies": {
         "mime-types": "~2.1.34",
         "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
       }
     },
-    "array-flatten": {
+    "node_modules/array-flatten": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
       "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
     },
-    "body-parser": {
+    "node_modules/body-parser": {
       "version": "1.20.1",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
       "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
-      "requires": {
+      "dependencies": {
         "bytes": "3.1.2",
         "content-type": "~1.0.4",
         "debug": "2.6.9",
@@ -35,115 +49,159 @@
         "raw-body": "2.5.1",
         "type-is": "~1.6.18",
         "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
       }
     },
-    "busboy": {
+    "node_modules/busboy": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
       "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
-      "requires": {
+      "dependencies": {
         "streamsearch": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=10.16.0"
       }
     },
-    "bytes": {
+    "node_modules/bytes": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "call-bind": {
+    "node_modules/call-bind": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
       "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "requires": {
+      "dependencies": {
         "function-bind": "^1.1.1",
         "get-intrinsic": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "charenc": {
+    "node_modules/charenc": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
-      "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="
+      "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
+      "engines": {
+        "node": "*"
+      }
     },
-    "content-disposition": {
+    "node_modules/content-disposition": {
       "version": "0.5.4",
       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
       "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
-      "requires": {
+      "dependencies": {
         "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
       }
     },
-    "content-type": {
+    "node_modules/content-type": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "cookie": {
+    "node_modules/cookie": {
       "version": "0.5.0",
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "cookie-signature": {
+    "node_modules/cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
     },
-    "cors": {
+    "node_modules/cors": {
       "version": "2.8.5",
       "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
       "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
-      "requires": {
+      "dependencies": {
         "object-assign": "^4",
         "vary": "^1"
+      },
+      "engines": {
+        "node": ">= 0.10"
       }
     },
-    "crypt": {
+    "node_modules/crypt": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
-      "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="
+      "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
+      "engines": {
+        "node": "*"
+      }
     },
-    "debug": {
+    "node_modules/debug": {
       "version": "2.6.9",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-      "requires": {
+      "dependencies": {
         "ms": "2.0.0"
       }
     },
-    "depd": {
+    "node_modules/depd": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "destroy": {
+    "node_modules/destroy": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
-      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
     },
-    "ee-first": {
+    "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
     },
-    "encodeurl": {
+    "node_modules/encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "escape-html": {
+    "node_modules/escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
       "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
     },
-    "etag": {
+    "node_modules/etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "express": {
+    "node_modules/express": {
       "version": "4.18.2",
       "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
       "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
-      "requires": {
+      "dependencies": {
         "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
         "body-parser": "1.20.1",
@@ -175,21 +233,27 @@
         "type-is": "~1.6.18",
         "utils-merge": "1.0.1",
         "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
       }
     },
-    "express-fileupload": {
+    "node_modules/express-fileupload": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.4.0.tgz",
       "integrity": "sha512-RjzLCHxkv3umDeZKeFeMg8w7qe0V09w3B7oGZprr/oO2H/ISCgNzuqzn7gV3HRWb37GjRk429CCpSLS2KNTqMQ==",
-      "requires": {
+      "dependencies": {
         "busboy": "^1.6.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
       }
     },
-    "finalhandler": {
+    "node_modules/finalhandler": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
       "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
-      "requires": {
+      "dependencies": {
         "debug": "2.6.9",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
@@ -197,210 +261,302 @@
         "parseurl": "~1.3.3",
         "statuses": "2.0.1",
         "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
       }
     },
-    "forwarded": {
+    "node_modules/forwarded": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
-      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "fresh": {
+    "node_modules/fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "function-bind": {
+    "node_modules/function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
     },
-    "get-intrinsic": {
+    "node_modules/get-intrinsic": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
       "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
-      "requires": {
+      "dependencies": {
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
         "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "has": {
+    "node_modules/has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
       "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "requires": {
+      "dependencies": {
         "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
       }
     },
-    "has-symbols": {
+    "node_modules/has-symbols": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
-    "http-errors": {
+    "node_modules/http-errors": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
       "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-      "requires": {
+      "dependencies": {
         "depd": "2.0.0",
         "inherits": "2.0.4",
         "setprototypeof": "1.2.0",
         "statuses": "2.0.1",
         "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
       }
     },
-    "iconv-lite": {
+    "node_modules/iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
       "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-      "requires": {
+      "dependencies": {
         "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
       }
     },
-    "inherits": {
+    "node_modules/inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
-    "ipaddr.js": {
+    "node_modules/ipaddr.js": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
-      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "engines": {
+        "node": ">= 0.10"
+      }
     },
-    "is-buffer": {
+    "node_modules/is-buffer": {
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
       "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
     },
-    "md5": {
+    "node_modules/md5": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
       "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
-      "requires": {
+      "dependencies": {
         "charenc": "0.0.2",
         "crypt": "0.0.2",
         "is-buffer": "~1.1.6"
       }
     },
-    "media-typer": {
+    "node_modules/media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "merge-descriptors": {
+    "node_modules/merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
       "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
     },
-    "methods": {
+    "node_modules/methods": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "mime": {
+    "node_modules/mime": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
     },
-    "mime-db": {
+    "node_modules/mime-db": {
       "version": "1.52.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "mime-types": {
+    "node_modules/mime-types": {
       "version": "2.1.35",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "requires": {
+      "dependencies": {
         "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
       }
     },
-    "ms": {
+    "node_modules/ms": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
     },
-    "negotiator": {
+    "node_modules/negotiator": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
-      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "object-assign": {
+    "node_modules/object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
     },
-    "object-inspect": {
+    "node_modules/object-inspect": {
       "version": "1.12.2",
       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
-      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
+      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
-    "on-finished": {
+    "node_modules/on-finished": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
       "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
-      "requires": {
+      "dependencies": {
         "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
       }
     },
-    "parseurl": {
+    "node_modules/parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "path-to-regexp": {
+    "node_modules/path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
       "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
     },
-    "proxy-addr": {
+    "node_modules/proxy-addr": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
       "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
-      "requires": {
+      "dependencies": {
         "forwarded": "0.2.0",
         "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
       }
     },
-    "qs": {
+    "node_modules/qs": {
       "version": "6.11.0",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
       "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
-      "requires": {
+      "dependencies": {
         "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "range-parser": {
+    "node_modules/range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
-    "raw-body": {
+    "node_modules/raw-body": {
       "version": "2.5.1",
       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
       "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-      "requires": {
+      "dependencies": {
         "bytes": "3.1.2",
         "http-errors": "2.0.0",
         "iconv-lite": "0.4.24",
         "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
       }
     },
-    "safe-buffer": {
+    "node_modules/safe-buffer": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
     },
-    "safer-buffer": {
+    "node_modules/safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
-    "send": {
+    "node_modules/send": {
       "version": "0.18.0",
       "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
       "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
-      "requires": {
+      "dependencies": {
         "debug": "2.6.9",
         "depd": "2.0.0",
         "destroy": "1.2.0",
@@ -415,78 +571,106 @@
         "range-parser": "~1.2.1",
         "statuses": "2.0.1"
       },
-      "dependencies": {
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
-        }
+      "engines": {
+        "node": ">= 0.8.0"
       }
     },
-    "serve-static": {
+    "node_modules/send/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+    },
+    "node_modules/serve-static": {
       "version": "1.15.0",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
       "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
-      "requires": {
+      "dependencies": {
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
         "parseurl": "~1.3.3",
         "send": "0.18.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
       }
     },
-    "setprototypeof": {
+    "node_modules/setprototypeof": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
       "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
     },
-    "side-channel": {
+    "node_modules/side-channel": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
       "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-      "requires": {
+      "dependencies": {
         "call-bind": "^1.0.0",
         "get-intrinsic": "^1.0.2",
         "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "statuses": {
+    "node_modules/statuses": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "streamsearch": {
+    "node_modules/streamsearch": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
-      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
+      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
     },
-    "toidentifier": {
+    "node_modules/toidentifier": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "engines": {
+        "node": ">=0.6"
+      }
     },
-    "type-is": {
+    "node_modules/type-is": {
       "version": "1.6.18",
       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
       "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-      "requires": {
+      "dependencies": {
         "media-typer": "0.3.0",
         "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
       }
     },
-    "unpipe": {
+    "node_modules/unpipe": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     },
-    "utils-merge": {
+    "node_modules/utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
     },
-    "vary": {
+    "node_modules/vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
     }
   }
 }

BIN
img/web_009.png


BIN
img/web_010.png


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است