Что такое java collection framework?

Реализация List

Будучи подтипом Collection, все методы в интерфейсе Collection также доступны в Listinterface.

Поскольку List – это интерфейс, вам необходимо создать конкретную реализацию интерфейса, чтобы использовать его. Вы можете выбирать между следующими реализациями List в API коллекций Java:

  • java.util.ArrayList
  • java.util.LinkedList
  • java.util.Vector
  • java.util.Stack

Также есть параллельные реализации List в пакете java.util.concurrent.

Вот несколько примеров того, как создать экземпляр List:

List listA = new ArrayList();
List listB = new LinkedList();
List listC = new Vector();
List listD = new Stack();

Перспективы NFT-одежды

Цифровой мир становится все более значимым, и бренды стремятся усилить цифровое взаимодействие со своими клиентами. И если через 10-20 лет цифровые двойники в метавселенных станут такой же нормой, как сейчас аккаунты в соцсетях, бренды хотят быть к этому готовыми. 

По прогнозам Morgan Stanley, спрос на цифровые предметы роскоши в текущем десятилетии резко возрастет, и этот рынок достигнет оценки в более чем $50 млрд к 2030 году. При этом норма прибыли составит около 75% от выручки — брендам не придется тратиться на сырье, производство и логистику. Даже на разработке можно сэкономить: ведь у брендов уже есть обширный архив прошлых коллекций, которые можно оцифровать. 

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

Но у светлого будущего NFT-моды немало проблем. Главные из них:

  • Нишевый характер продукта — цифровая одежда воспринимается большинством как интересное дополнение к их виртуальному персонажу;
  • Метавселенные сейчас только в начале своего развития. До запуска полноценных метавселенных еще далеко, и пока с цифровой одеждой не очень справляются технологии дополненной реальности. Например, компании Dress-X требуется от трех до пяти часов, чтобы вручную нарисовать цифровую одежду для аватара пользователя. 

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

Коллекция Java: Упражнения TreeMap [26 упражнений с решением]

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

2. Напишите Java-программу для копирования содержимого Tree Map в другую Tree Map. Нажмите меня, чтобы увидеть решение

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

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

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

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

7. Напишите программу на Java для сортировки ключей в Tree Map с помощью компаратора. Нажмите меня, чтобы увидеть решение

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

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

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

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

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

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

14. Напишите программу на Java, чтобы получить часть этой карты, ключи которой меньше (или равны, если inclusive true) данного ключа. Нажмите меня, чтобы увидеть решение

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

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

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

18. Напишите программу на Java, чтобы получить представление NavigableSet о ключах, содержащихся в карте. Нажмите меня, чтобы увидеть решение

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

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

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

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

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

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

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

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

Кратко по каждой коллекции

Интерфейс итератора (Iterator)

Итератор предоставляет методы для перебора элементов любой коллекции. Мы можем получить экземпляр итератора из коллекции с помощью метода . Итераторы позволяют удалить элементы из базовой коллекции во время выполнения итерации.

Интерфейс множества (Set)

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

Платформа Java содержит три реализации Set : и нтерфейс не позволяет осуществлять произвольный доступ к элементу в коллекции. Мы можем использовать итератор или цикл по каждому элементу для перебора элементов.

Интерфейс Список (List)

Список представляет собой упорядоченный набор элементов и может содержать повторяющиеся элементы. Вы можете получить доступ к любому элементу по индексу. Список представляет собой динамический массив. Список является одним из наиболее используемых типов коллекций. и классы являются реализацией интерфейса .

Вот небольшой пример использования:

Java

List strList = new ArrayList<>();
//добавить в конец
strList.add(0, «0»);
//добавить элемент в определенное место
strList.add(1, «1»);
//заменить элемент
strList.set(1, «2»);
//удалить элемент
strList.remove(«1»);

1
2
3
4
5
6
7
8
9

List strList=newArrayList<>();

//добавить в конец

strList.add(,»0″);

//добавить элемент в определенное место

strList.add(1,»1″);

//заменить элемент

strList.set(1,»2″);

//удалить элемент

strList.remove(«1»);

Интерфейс Очередь (Queue)

Очередь — коллекция, которая используется для хранения нескольких элементов.

В очереди обычно, но не обязательно, элементы располагаются по принципу FIFO (first-in, first-out = первый вошел, первый вышел). В очереди FIFO, все новые элементы вставляются в конец очереди.

Интерфейс Dequeue

Коллекция Dequeue поддерживает вставку элемента и удаление элемента как в начало, так и в конец коллекции. Название Deque это сокращение от «двухконцевой очереди» и, как правило, произносится как «deck». Большинство реализаций DEQUE не устанавливают ограничения на количество элементов.

Этот интерфейс определяет методы для доступа к элементам на концах дека. Методы предоставляются для вставки, удаления, извлечения элемента.

Интерфейс Map

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

Платформа Java содержит три реализации Map: и 

Интерфейс ListIterator

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

Интерфейс SortedMap

SortedMap содержит элементы в порядке возрастания ключей. Эта Map является аналогом SortedSet. SortedMap используются для естественно упорядоченных пар ключ/значение, например, словарей и телефонных справочников.

Что я могу сделать с помощью AJAX ?

Смысл AJAX — в интерактивности и быстром времени отклика.

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

Например, дерево, узлы которого подгружаются по мере раскрытия.

Например, при редактировании статьи — каждые 10 минут результаты автосохраняются на сервере.

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

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

Подсписок списка

Метод subList () может создавать новый List с подмножеством элементов из исходного List.

Метод subList () принимает 2 параметра: начальный индекс и конечный индекс. Начальный индекс – это индекс первого элемента из исходного списка для включения в подсписок.

Конечный индекс является последним индексом подсписка, но элемент в последнем индексе не включается в подсписок. Это похоже на то, как работает метод подстроки Java String.

List list      = new ArrayList();

list.add("element 1");
list.add("element 2");
list.add("element 3");
list.add("element 4");

List sublist = list.subList(1, 3);

После выполнения list.subList (1,3) подсписок будет содержать элементы с индексами 1 и 2.

Преобразовать list в set

Вы можете преобразовать список Java в набор(set), создав новый набор и добавив в него все элементы из списка. Набор удалит все дубликаты.

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

List list = new ArrayList();

list.add("element 1");
list.add("element 2");
list.add("element 3");
list.add("element 3");

Set set = new HashSet();
set.addAll(list);

Обратите внимание, что список содержит элемент String 3 два раза. Набор будет содержать эту строку только один раз

Таким образом, результирующий набор будет содержать строки:  ,  and  .

Общие списки

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

List<MyObject> list = new ArrayList<MyObject>();

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

MyObject myObject = list.get(0);

for(MyObject anObject : list){
   //do someting to anObject...
}

Сортировка

Вы можете отсортировать список с помощью метода Collections sort ().

Если Список содержит объекты, которые реализуют интерфейс Comparable (java.lang.Comparable), тогда эти объекты можно сравнивать. В этом случае вы можете отсортировать список следующим образом:

List<String> list = new ArrayList<String>();

list.add("c");
list.add("b");
list.add("a");

Collections.sort(list);

Класс Java String реализует интерфейс Comparable, вы можете отсортировать их в естественном порядке, используя метод Collections sort ().

Сортировка списка с помощью Comparatorimplementation

Если объекты не реализуют интерфейс Comparable или если вы хотите отсортировать объекты в порядке, отличном от их реализации compare (), вам необходимо использовать Comparatorimplementation (java.util.Comparator).

public class Car{
    public String brand;
    public String numberPlate;
    public int noOfDoors;

    public Car(String brand, String numberPlate, int noOfDoors) {
        this.brand = brand;
        this.numberPlate = numberPlate;
        this.noOfDoors = noOfDoors;
    }
}

Вот код сортировки:

List<Car> list = new ArrayList<>();

list.add(new Car("Volvo V40" , "XYZ 201845", 5));
list.add(new Car("Citroen C1", "ABC 164521", 4));
list.add(new Car("Dodge Ram" , "KLM 845990", 2));

Comparator<Car> carBrandComparator = new Comparator<Car>() {
    @Override
    public int compare(Car car1, Car car2) {
        return car1.brand.compareTo(car2.brand);
    }
};

Collections.sort(list, carBrandComparator);

Возможно реализовать Comparator с использованием Java Lambda. Вот пример, который сортирует объекты List of Car с использованием трех различных реализаций интерфейса Comparator, каждая из которых сравнивает экземпляры Car по своему полю:

List<Car> list = new ArrayList<>();

list.add(new Car("Volvo V40" , "XYZ 201845", 5));
list.add(new Car("Citroen C1", "ABC 164521", 4));
list.add(new Car("Dodge Ram" , "KLM 845990", 2));


Comparator<Car> carBrandComparatorLambda      =
    (car1, car2) -> car1.brand.compareTo(car2.brand);

Comparator<Car> carNumberPlatComparatorLambda =
    (car1, car2) -> car1.numberPlate.compareTo(car2.numberPlate);

Comparator<Car> carNoOfDoorsComparatorLambda  =
    (car1, car2) -> car1.noOfDoors - car2.noOfDoors;

Collections.sort(list, carBrandComparatorLambda);
Collections.sort(list, carNumberPlatComparatorLambda);
Collections.sort(list, carNoOfDoorsComparatorLambda);

Методы интерфейса java.util.Collection

Метод Описание
Iterator<E> iterator() Возвращает итератор для обращения к элементам набора данных.
int size() Возвращает количество элементов в наборе данных.
boolean isEmpty() Возвращает значение true, если набор пустой.
boolean contains (Object obj) Возвращает true, если набор содержит объект, эквивалентный obj.
boolean containsAll (Collection<?> other) Возвращает true, если текущий набор содержит все объекты набора данных other.
boolean add (Object element) Добавляет элемент в набор. Возвращает true, если в результате вызова метода набор
данных изменился.
boolean addAll (Collection<? extends E> other) Добавляет все элементы в набор. Возвращает true, если в результате вызова метода набор
данных изменился.
boolean remove (Object obj) Удаляет объект obj. Возвращает true, если в результате вызова метода набор
данных изменился.
boolean removeAll (Collection<?> other) Удаляет из текущего набора данных все элементы, содержащиеся в наборе other. Возвращает true,
если в результате вызова метода набор данных изменился.
void clear () Удаляет из текущего набора данных все элементы.
boolean retainAll (Collection<?> other) Удаляет из набора данных элементы, не совпадающие с теми, которые содержатся в наборе other.
Возвращает true, если в результате вызова метода набор данных изменился.
Object[] toArray () Возвращает массив с объектами из набора данных.

Пример. Gmail.

Раз уж взялись за Google — рассмотрим почтовый сервис той же компании, http://gmail.com.

На момент его появления он явился единственным открытым почтовым сервисом, использующим AJAX для следующих фич.

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

Результат: обширная популярность, высокий спрос на account’ы с момента открытия.

Все о NFT

Незаменяемый токен (NFT) это индивидуальный цифровой жетон, существующий на блокчейне. В текущий период много невзаимозаменяемых токенов выпускаются по стандарту ERC-721, предназначенном для цепочки Ethereum. Но существуют и другие стандарты, например, ERC-1155 и ERC-998. NFT-токены также поддерживаются другими блокчейнами, включая BSC, MATIC, TRON, EOS, NEO.

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

Невзаимодействующие токены используются для создания, поддающегося проверке цифрового дефицита в конкретных приложениях, которые требуют уникальных цифровых элементов. Например, для блокчейн-игр и коллекционирования. NFT также можно использовать для представления внутриигровых активов, которые контролируются пользователем, а не разработчиком игры. Такие токены или цифровые предметы могут на самом деле пережить игру, для которой они были изначально созданы, и найти включение в отдельные будущие игры. Еще одно применение — это цифровое искусство. NFT позволяет каждому автору доказать подлинность и право собственности на произведения искусства, расположенными на блокчейне. Каждая творческая личность может создать собственный NFT и продавать контент на децентрализованных рынках. NFT один из лучших способов заработать криптовалюту, не инвестируя в нее напрямую. Это почти тоже самое что открыть магазин на Ebay.

Есть масса причин для покупки НФТ. Каждый токен уникален, он единственный в своем роде. Вы не можете сделать другой NFT, который является тем же номером токена на том же смарт-контракте. Это гарантируется блокчейном и может быть проверено любым пользователем. Владелец NFT имеет все полномочия на использование этого изображения и актива. Вы будете единственным владельцем коллекционного предмета, который можно перепродать. Но, возможно, со временем, его ценность будет только расти. Покупая NFT для перепродажи, вы можете заработать тысячи долларов. Есть много людей, которые делают так каждый день и зарабатывают этим на жизнь. Никто не может изменить метаданные на токене, никто не может удалить ваше изображение или имя токена. Это означает, что он никогда не изменится, он никогда не будет удален, он не может быть снят с блокчейна. Именно это придает ему такую большую ценность.

Интерфейс List и его реализации — ArrayList и LinkedList

List — это упорядоченная коллекция, наиболее часто используемая в Java Collections Framework. Этот интерфейс контролирует, где вставлен каждый элемент списка. При работе с List пользователю доступны элементы списка по их целочисленному индексу (позиции в списке).

Работа с интерфейсом List

Интерфейс List имеет две стандартные реализации — ArrayList и LinkedList.

Смысл в том, что можно написать и другие реализации, но в JDK уже есть две, которые доступны «‎‎из коробки».

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

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

Вторая имплементация интерфейса List — класс LinkedList

Для наглядности различий в цикломатической сложности между двумя классами рассмотрим таблицу:

Различия в цикломатической сложности между классами LinkedList и ArrayList

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

Так же дела обстоят с оператором . Цикломатическая сложность этой операции для LinkedList будет ниже только в том случае, если сам индекс будет равен нулю. Для всех остальных случаев разумнее использовать именно ArrayList.

Это же касается и операции : для класса LinkedList ее цикломатическая сложность будет вдвое меньше, чем для ArrayList. Забегая наперед скажу, что именно ArrayList используют в подавляющем случае работ в интерфейсе List.

Реализации интерфейса Map

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

interface Мар<К, V>

Здесь К указывает тип ключей, а V — тип хранимых значений.

Иерархия классов очень похожа на иерархию Set’а:

HashMap — основан на хэш-таблицах, реализует интерфейс Map (что подразумевает хранение данных в виде пар ключ/значение). Ключи и значения могут быть любых типов, в том числе и null. Данная реализация не дает гарантий относительно порядка элементов с течением времени. Хорошая статья http://habrahabr.ru/post/128017/

LinkedHashMap —  расширяет класс HashMap. Он создает связный список элементов в карте, расположенных в том порядке, в котором они вставлялись. Это позволяет организовать перебор карты в порядке вставки. То есть, когда происходит итерация по коллекционному представлению объекта класса LinkedHashMap, элементы будут возвращаться в том порядке, в котором они вставлялись. Вы также можете создать объект класса LinkedHashMap, возвращающий свои элементы в том порядке, в котором к ним в последний раз осуществлялся доступ. Рекомендую так же прочитать http://habrahabr.ru/post/129037/

TreeMap — расширяет класс AbstractMap и реализует интерфейс NavigatebleMap. Он создает коллекцию, которая для хранения элементов применяет дерево. Объекты сохраняются в отсортированном порядке по возрастанию. Время доступа и извлечения элементов достаточно мало, что делает класс TreeMap блестящим выбором для хранения больших объемов отсортированной информации, которая должна быть быстро найдена.Моя статья про TreeMap http://www.quizful.net/post/Java-TreeMap

WeakHashMap — коллекция, использующая слабые ссылки для ключей (а не значений). Слабая ссылка (англ. weak reference) — специфический вид ссылок на динамически создаваемые объекты в системах со сборкой мусора. Отличается от обычных ссылок тем, что не учитывается сборщиком мусора при выявлении объектов, подлежащих удалению. Ссылки, не являющиеся слабыми, также иногда именуют «сильными».http://ru.wikipedia.org/wiki/%D0%A1%D0%BB%D0%B0%D0%B1%D0%B0%D1%8F_%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0

Подводя итог: императивное и декларативное программирование

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

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

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

  • Императивное и декларативное программирование
  • В чем разница между императивным, процедурным и структурированным программированием?
  • Императивный и (функциональный) декларативный JS на практике
  • Map, Reduce, и Filter в JavaScript

Функции высшего порядка

Функция высшего порядка — это функция, которая принимает другую функцию в качестве аргумента или возвращает функцию в результате.

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

const double = function(x) {  return x * 2;}const timesTwo = double;timesTwo(4); // результат: возвращает 8

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

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

function sayHi() {  alert('Hi!');}function greet(greeting) {  greeting();}greet(sayHi); // "Hi!"

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

Функции высшего порядка также могут возвращать другую функцию:

function whenMeetingJohn() {  return function() {    alert('Hi!');  }}var atLunchToday = whenMeetingJohn();atLunchToday(); // "Hi!"
Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Мебельный VAG
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: