9 крутых нейросетей, которые создают картинки по тексту

Converting an image into ascii art masterpiece - jonathan petitcolas

How to translate pixels to ASCII

Now that we’ve seen how images are represented, it’s time to talk about how a pixel can be transformed into an actual ASCII character. To understand this, we must first take a look at pixel color intensity. This value refers to the sum of all the pixel’s channels, divided by the sum of the maximum values the channels can have (in this case 255).

The first line imports static types needed for clarity. If you don’t know what they are, check out my article on type hints.

In this code snippet I’ve defined a new type, a of four integers each representing one of the channels in a RGBA pixel. I’ve then defined a function that extracts the given pixel’s intensity. It first sums all the channel values and then divides the result by the maximum value a pixel’s channels can reach to effectively get an intensity percentage.

Once we’ve calculated the pixel’s intensity, it’s time to map it to an ASCII character. For this we have to define a character set we’ll be using to represent the pixels.

The character set is ordered from the lightest, the space, to the heaviest, the . This means that the more intense a pixel is, the more space its corresponding ASCII character occupies.

The function maps the given pixel intensity to a character in the set. The result of is rounded since indexes must be integers.

Now, lets glue these code snippets together with a simple script:

Mapping the Pixels to Gray Scale Values

Now that we have a list of grayscale values for every pixel, we can map each of these value to a different character. Reason behind this mapping is simple: some characters are darker than others. For instance, is darker than , which occupies less space on screen.

The following character ramp is generally used for this conversion:

Hence, mapping a gray scale value to its equivalent character can be done via:

We retrieve the corresponding character using a cross-shaped product: gray scale of 0 (black) should be , and a white pixel (gray scale of 255) should be a space. We substract 1 to as arrays start at 0 index.

Let’s translate our input image into pure characters:

We use a tag in order to keep aspect ratio of our picture, as it uses a monospaced font.

Calling the method at the end of our callback, we get the following result:

At first glance, it seems it doesn’t work. Yet, if we scroll horizontally, we notice some strings wandering through the screen. Our picture seems to be on a single line. And indeed: all our values are on a single dimensional array. Hence, we need to add a break line every value:

Result is now far better, except for a detail…

Visual improvements using HTML

We’ve already seen how to convert an image to its ASCII representation, but it would be nicer of you could save the result into an actual file. But why HTML?

  • It’s supported by all web browsers.
  • You can easily zoom in and out depending on the scale of the image.
  • It can be still composed of only ASCII characters.

Let’s write a function to save the resulting image into an HTML file:

Now that we’ve completed the our image converter, let’s take some time to look at a few cool pictures and their ASCII version:

Photo by Mathew Schwartz on Unsplash
ASCII version of original image by Mathew Schwartz on Unsplash
Photo by Jacques Bopp on Unsplash
ASCII version of original image by Jacques Bopp on Unsplash
Photo by freestocks on Unsplash
ASCII version of original image by freestocks on Unsplash

Here’s the link to the project’s GitHub repository I’ve based this article on. I’ll also directly include the source code in the gist below in case you were short on time:

Complete script for image conversion

In case someone is interested, I’ve also set up a simple free website that converts your images into ASCII. I disclaim though that this is not a serious project and may contain bugs and vulnerabilities, so don’t even remotely think about relying on it for anything.

Что такое «нейросеть»

Зачастую нейросеть иллюстрируют именно так. И в этом есть доля правды, ведь данные передаются от одного нейрона к другому по цепочке.

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

Каждый нейрон преобразует несколько входных фактов в один выходной. К примеру:

1. Есть два факта, один из которых важнее второго.2. Нейрон получает эти два факта, сравнивает и в случае приоритетности одного выдаёт определённый результат.3. Этот результат, в свою очередь, является одним из входных данных для следующего нейрона.

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

Наглядная схема обучения нейросети. Взято отсюда.

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

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

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

Работа нейросети похожа на работу мозга, когда человек приходит к определённому выводу на основании полученной извне информации.

Help

1. How do I use the converter?
First you click the Choose file or Browse button at the top.
Now a window pops up, where you choose an image file from your device, which you want to convert.

Next, you decide which characters you want the HTML image to use (default is ‘0’ and ‘1’). Any characters can be chosen by simply typing them (without space!) in the input field.

Now you need to decide whether these characters should appear randomly (0110100) or in sequence (01010101).
The next step is to decide the width of your HTML image. The default has been set to 125 characters. Higher number gives more detail, but also larger image size.
After that, you can pick the font size of the generated image. Smaller font gives higher detail.

Last comes the background colour. You can choose any colour by clicking on the colour picker. For best contrast, picking black is recommended.

Now just hit Convert! and you will see an HTML representation of your image. Please note that this can take some time if your chosen image is very large.

2. What image formats are supported?
You can convert pictures of the formats JPG, PNG, GIF, WEBP and BMP.

3. How do I save the text-image as a picture?
The recommended way is to take a screenshot and then crop the part with just the text-image:

  • Windows — Press Shift + Windows button + S simultaneously.
  • Mac — Press Shift + Command + 4 simultaneously.
  • Android — Press Power + Volume Down buttons simultaneously.
  • iPhone — See Apple’s help page for details.

4. Can’t I just share the text-image with my friends?
You can now! Click the Create public share link button underneath the converted text-image, then click on the Copy button to put the link URL in your clipboard.
Now you can simply paste it in messages to your friends, or on Twitter and Facebook.
Note that the text-image will only be stored on this server for 5 days, so find another way if you want it saved permanently.

5. How do I copy the HTML code for the image?
If you right-click in the window with the image, and choose View Source, you can cut and paste the part where the image is. It has been marked with a beginning and an end comment.

6. Why do I get an Error message?
The server times out the image upload if it takes too long. Try using an image with smaller size, or get a better internet connection.

7. Why is the converted image missing part of the end?
Sometimes the script times out before the whole image sent to the server, which results in cut-off images. Either try converting it again, or try a smaller image.

8. Where can I get the converter program?
You can download the Windows application here.
The online web converter requires Pike to run, and your own web server. Source code is found here.

9. Why is the converter so slow?
It’s not. In most cases, the delay is caused by the time it takes to transfer the image from your device to this website, because you are trying to use a very large image. This is a mistake, and the solution is to make the image smaller before converting it. Using an image resizing app like IrfanView, you can open your picture and use the Save as function to make a copy of it as JPEG in 60% quality, which can reduce its size up to 10 times! The converted text-image will still look as good, but converting it will be 10 times faster.

10. I liked the old page design better, where did it go?
The old site and converters are still available here.

11. How do I contact you?
See the About page.

Постановка задачи

Приложение должно соответствовать следующим требованиям:

  • наличие двух способов загрузки исходного изображения: через поле выбора файла и перетаскиванием в специальную область (далее будем называть «область приема»);
  • отсутствие сложных настроек. Только самое необходимое: цвет фона, используемый текст и размер шрифта;
  • возможность обработки изображений с прозрачным фоном;
  • работа должна происходить только в браузере, без обращений к серверу и без перезагрузки страницы.

Понятно, что вопрос о поддержке старых браузеров не встает.

Для начала, набросаем html-разметку. Страница приложения делится на три логических части:

Deep Dream Generator

Одним из лучших генераторов искусств с искусственным интеллектом является Deep Dream Generator от Aifnet. Deep Dream — один из самых популярных на рынке генераторов изображений с искусственным интеллектом. Это онлайн-инструмент, который позволяет создавать реалистичные изображения с помощью искусственного интеллекта.

Deep Dream использует нейронную сеть, обученную на миллионах изображений. Он прост в использовании, вам нужно только загрузить изображение, прежде чем инструмент сгенерирует новое изображение на основе оригинала.

Одним из основных применений Deep Dream является использование его для создания произведений искусства, поскольку он использует разные стили рисования для создания изображений, которые кажутся из разных мест или периодов времени.

Инструмент позволяет выбрать категорию, например, животных или пейзажи, прежде чем на ее основе будет создано реалистичное изображение. Помимо всего этого, Deep Dream позволяет вам выбрать три стиля: Deep Style, Thin Style или Deep Dream. После выбора стиля вы можете предварительно просмотреть изображение.

Они также выпустили собственное программное обеспечение Text to Image, которое они назвали Text 2 Dream.

Вот некоторые из основных особенностей Deep Dream:

– Создает реалистичные изображения с помощью ИИ– Нейронная сеть обучена на миллионах изображений– Различные стили рисования– Категории изображений– Три отдельных стиля– Text 2 Image

Размеры изображения и CSS

В HTML5 приемлемы оба вышеприведенных способа задания размеров изображения.
Однако, вместо того чтобы использовать атрибуты width и height элемента <img>, как указано выше, целесообрзнее установить размер с помощью CSS. Это может дать вам дополнительную гибкость при отображениии картинки на странице.

Если изображение не помещается внутри области содержимого при просмотре на устройстве с небольшим экраном (например, мобильный телефон), пользователю приходится прокручивать страницу по горизонтали или уменьшать масштаб, чтобы увидеть картинку полностью, при этом, он испытывает большие неудобства.
В таких случаях предпочтительнее указать в атрибуте style значения max-width или max-height вместо абсолютных размеров.
В следующем примере мы используем max-width:100% для того, чтобы изображение не было слишком большим для своего контекста. При использовании только max-width (без использования max-height), браузер будет масштабировать изображение пропорционально. Другими словами, высота будет масштабируется вместе с шириной, а изображение не будет искажаться.

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

Атрибуты «width» и «height»

Вы уже знаете, что браузер загружает изображения после того, как загрузит HTML-документ и начнет отображать веб-страницу. И если вы отдельно не укажете размеры изображения, то браузер не будет их знать до тех пор, пока не загрузит рисунок. В этом случае вместо изображения сначала отображается квадратик, а после загрузки графического файла происходит обновление страницы с соответствующим перемещением текста, других объектов страницы и потерей времени. Если же размеры заданы, то браузер оставляет место для изображения и страница загружается быстрее. Вы также можете указать значения атрибутов width и height, которые меньше или больше, чем фактические размеры изображения, и браузер установит пропорции рисунка так, чтобы они соответствовали новым размерам.
Их значения можно указывать в пикселах или процентах от размера окна (в этом случае после размера ставится знак %). Если после числовых значений атрибутов размерность не указана явно то, по-умолчанию, браузер интерпретирует эти величины в пикселях.

Пример: использования атрибутов width и height

  • Результат
  • HTML-код
  • Попробуй сам »
Если вам нужно значительно изменить размеры изображения, то используйте специальные графические редакторы для работы с изображениями. Они смогут изменить размеры изображения вовсе без искажений.

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

Если вы используете атрибуты width и height для того, чтобы изменить размеры изображения в браузере, то можно сказать, что вы применяете их для оформления веб-страницы, а в этом случае, лучше использовать CSS, что позволит добиться тех же результатов. Вы можете использовать атрибут style указав свойства width и height изображения:

What an image actually is

First of all, is important to clarify how an image is represented in computer systems. Pictures are usually stored in formats such as or on the disk. All these file types have a similar structure: they’re roughly composed of an and a data section. The former stores useful information about the image such as its , whereas the latter stores the actual pixel data.

The actual image you see is composed of pixels, the smallest addressable element of a raster image which we’re all familiar with. They’re usually represented as a set of channels, also referred as colors. Among the most common color values there are the classic RGB (Red Green Blue) and RGBA (Red Green Blue Alpha). The difference between the two is that the latter has an additional channel, called “alpha”, that specifies the image opacity. RGBA is what we’ll be working with since it can also be used to represent a void background.

Обработка изображения

Весь процесс можно разбить на несколько этапов:

  1. получение данных об исходном изображении. А точнее — нам нужен цвет каждого пикселя;
  2. расчет размеров символов, при помощи которых будет формироваться арт;
  3. расчет цвета каждого символа и его цвета;
  4. непосредственно генерация арта;
  5. представление арта в виде изображения, что бы пользователь мог сохранить плод своих стараний.

Получение данных об исходном изображении

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

Теперь у нас есть необходимая информация. Вот только представлена она не в самой лучшей форме. Это одномерный массив, где первые четыре элемента описывают первый пиксель (rgba), элементы с пятого по восьмой — второй пиксель и т.д. до конца. Как с таким работать, я слабо представляю. Поэтому давайте приведем эту кучу чисел в человеческий вид.

Теперь мы имеем двумерный массив где каждый пиксель представлен объектом. С ним и будем работать дальше.

Расчет размеров символа

Как получить точный размер символа? Не размер шрифта, а область, которую символ занимает на экране? Что бы не заморачиваться, просто создадим временный span с этим символом и замерим его размер.

Внимательный читатель скорее всего заметил, что учитывается не вся высота символа, а только 80%. Это сделано потому, что видимая часть буквы занимает не всю отводимую ей высоту. Из-за этого на итоговом изображении появляются пустые горизонтальные линии между строчками. Особенно они заметны, если буквы большого размера. Я пристрелялся, так что бы при разных размерах шрифта расстояние между строчками было минимальным — получилось 80%. Так и оставим.

Расчет положения и цвета символов

Теперь необходимо составить “карту символов” — список, содержащий информацию о каждом символе, из которых будет формироваться итоговое изображение. Необходимо знать координаты символа и его цвет.

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

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

Генерация арта

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

Отлично! Наш арт готов. Осталось только показать его пользователю.

Атрибут «src».

Собственно, по-настоящему обязательный атрибут у тега <img> только один — это атрибут src. Атрибут src (от англ. source — источник) позволяет указать путь к изображению, которое должно быть отображено в HTML-документе. URL — обязательный параметр, который указывает браузеру, где находится изображение. В основном на сайтах используется графика файловых форматов: JPEG, GIF, PNG, BMP и SVG.

Если изображение находится в том же каталоге, что и содержащий его HTML-документ, достаточно указать только имя этого файла, например:

Пример HTML:

Попробуй сам

Если изображение находится на том же сервере, что и содержащий его HTML-документ, но в другом каталоге, следует указать имя каталога и имя файла с изображением, например:

Если изображение находится не на том сервере, на котором находится содержащий его HTML-документ, необходимо указать полный адрес файла с изображением, например:

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

Turning an Image into Gray Colors

Now our image has been uploaded, we need to convert it into gray colors. Each pixel color can be broken into three distinct components: red, green, and blue values, as in hexadecimal () colors in CSS. Computing gray scale of a pixel is simply averaging these three values together.

However, human eye is not equally sensitive to these three colors. For instance, our eyes are very sensitive to green color, while blue is only slightly perceived. Hence, we need to ponderate each colors using different weights. After taking a look on the (very) detailed Grayscale Wikipedia Page, we can compute the grayscale value using the following formula:

So, we need to iterate on each of our picture pixel, extract its RGB components, and replace each component by its related grayscale value. Fortunately, working on a allows us to manipulate each pixel using function.

The loop requires some explanations. We retrieve each pixels in the object. However, it is a uni-dimensional array, each pixel being splitted into its four components: red, green, blue, and alpha (for transparency). We retrieve the RGB value from the three first data cells, compute our grayscale, and then, move on of 4 indexes to go at the start of the next pixel components.

In this snippet, we modified the original image data, causing our function to be impure. Indeed, I wasn’t able to find a way to update image data using a copy of our variable.

Adding a call to function at the end of our listener, we can upload a picture in gray colors:

DALL-E

У компании есть несколько продуктов, обученных с помощью нейросети: Kandinsky 2.0, ruDALL-E Kandinsky (XXL), ruDALL-E Malevich (XL) и ruDALL-E Emojich.

Поговорим о каждом по отдельности.

Kandinsky 2.0

Несколько примеров работ Kandinsky 2.0:

Запрос: Ярмарка на Красной Площади в Москве в 17-м веке в стиле Сурикова
Запрос: Древние истуканы, которым поклоняются древние люди

Dall e Kandinsky (XXL)

Русская text-to-image модель. Задача нейросети генерировать картинки с помощью текста. В этой версии модели больше параметров, чем в ruDALL-E XL. Содержит 12 миллиардов параметров.

Примеры работ:

Запрос: Картошка, стилизованная под аниме, с эффектами электрических разрядов, на фоне современного города в неоновом киберпанк стиле
Запрос: Сюрреализм, стиль

ruDALL-E Malevich (XL)

Содержит такую же архитектуру как и в ruDALL-E Kandinsky, но в малевиче 1.3 миллиарда параметров для генерации картинок.

Примеры:

Запрос: Шахматная ладья из изумрудного материала
Запрос: Картина Малевича

ruDALL-E Emojich

Модель создана на базе нейросети ruDALL-E (XL). Принцип работы тот же, только эта нейросеть создаёт эмодзи по описанию пользователя. Для обучения этой модели было собрано 2749 иконок эмодзи и соответствующих русскоязычных описаний.

Примеры работ:

Запрос: ГендальфЗапрос: Дональд Трамп из лего
Как пользоваться DALL-E в России?

  1. Нужно зарегистрироваться на любом сайте по приёму смс, выбрать номер зарубежной страны.
  2. Включить VPN страны, номер которой вы взяли.
  3. Зайти на сайт DALL-E и зарегистрироваться на этот номер.
  4. Получив смс в онлайн-сервисе вы сможете зарегистрироваться и войти в аккаунт.

Artbreeder

Плюсы Artbreeder

  • Бесплатные генерации. У него нет ограничений на количество генераций изображений. Но платные функции есть: быстрый рендер, улучшенное качество и так далее.
  • Общедоступен и имеет веб-версию. В других AI есть разные проблемы, где-то нужно копаться в коде, где-то платить. В Artbreeder эти проблемы решены.
  • Топ за свои деньги. Для бесплатного генератора изображений ИИ показывает отличный результат.
  • Удобная лицензия. По правилам компании, изображения, которые создаёт пользователь, никому не принадлежат. Это значит их можно легально использовать в своих целях.

Как создать коллаж в Artbreeder

Когда коллаж откроется пользователь увидит панель инструментов. Первое, что нужно сделать — ввести текстовый запрос на английском языке. Чем меньше параметров, тем проще ИИ понять ваш запрос. Параметры highly detailed, intricate, high definition, или другие, касающиеся детализации, увеличивают объём мелких деталей на картинке (шороховатости, вмятины, морщины, тени), что улучшает фотографичность.

Изображение по описанию

Под конкретные художественные стили лучше прописывать фамилии художников или название картин. Что это значит: Hogwarts лучше чем magic school, Vincent Willem van Gogh лучше чем Oily blurred images.

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

Изображение из клякс (Коллаж)

Из панели инструментов в левой части экрана собираем изображение из рандомных элементов. Это даёт контроль над композицией кадра.

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

Почему из приведённых параметров нейросеть решила сделать именно плакат? Попалось рандомное «зерно», о них мы поговорим дальше.

Далее вы можете прибавлять текст, загружать своё фото, которое найдёте в интернете и миксовать эти подходы.

зёрна в Artbreeder

Эта клавиша отвечает за «зерно». Зерно — это элемент контролируемой случайности у нейросетей. В нём заложены различные идея для реализации запроса, чтобы при одних и тех же вводных получать разные результаты.

Они влияют на: композицию, цветовую гамму, стилистику, содержание полотна(детали), интерпретацию исходников, связи внутри нейросети. По-простому: кнопка «другой вариант»

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

Artbreeder girl

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

Исключением являются знаменитости. Всё потому, что при обучении AI тренируются в том числе и на портретах, артах, фотографиях медийных людей, поэтому с ними всё проще.

WOMBO Dream

Генераторы искусства AI — это WOMBO Dream, приложение для создания AI NFT, разработанное канадским стартапом WOMBO. Многие считают его лучшим универсальным приложением для создания NFT.

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

Вот некоторые из основных особенностей WOMBO Dream:

– Сюрреалистичные дизайны– Бесплатное использование– Создание NFT– Превратите фотографии в видел– Различные художественные стили

+1
+1
+1
+1
+1

Просмотры: 1 878

Как работает инструмент преобразования изображения в текст?

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

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

  • Вход
  • Сканирование
  • Сегментация местоположения
  • Извлечение функций
  • Обучение и признание
  • Вывод

Средство извлечения изображений с низким разрешением:

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

Определить математический синтаксис:

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

Обрабатывает несколько языков:

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

Заключение

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

  • сейчас, если зайдет пользователь с устаревшим браузером, приложение ничего не скажет, просто не будет работать. Надо добавить проверку на поддержку используемых технологий. Так же необходимо добавить проверку вводимых пользователем данных;
  • если размер исходного изображения не кратен размеру символа, внизу и справа появляются пустые полосы. Необходимо решить эту проблему.
  • ну и кроссбраузерность. У меня была возможность проверить только в chromium 25, chrome 27, firefox 21, opera 12 и safari на айфоне (версию не нашел). В остальных браузерах надо тестировать и исправлять баги.

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

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

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

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