Результати пошуку
ITVDN: курси програмування
Відеокурси з
програмування
Підписка

300+ курсів за популярними IT-напрямками

Вибери свою IT спеціальність

Підписка
Підписка

300+ курсів за популярними IT-напрямками

Результати пошуку за запитом: видеокурс c*
Фундамент внутрішньої оптимізації. 5 залізних факторів

Автор: Андрій Афанасьєв

Введение В начале данной статьи хочу поздравить Вас и себя со своей первой публикацией в 2016 году. Искренне желаю встречать на своем пути побольше ценной и интересной информации, а также людей, которые будут делиться бесценным опытом и помогут таким образом в Вашем профессиональном росте:) А теперь можно приступить непосредственно и к теме данной публикации. Я не сомневаюсь, что многие уже успели перелопатить массу книг и статей о том, какой должна быть качественная внутренняя оптимизация, на что она влияет, какие тренды нас ждут в наступившем году, поскольку такой информации в Интернете целые массивы. Но меня это не остановило. Я уверен, что данный материал обязательно откроет что-то новое, позволит расставить акценты и сосредоточить внимание на самом главном. Тем более, кто дочитает эту статью до конца, получит небольшой, но приятный бонус:) От слов к делу Самый встречаемый вопрос, особенно среди новичков, звучит так: ”Внутренняя оптимизация - такой трудоемкий процесс, так много факторов и пунктов проверки. Подскажи, на что стоит обращать внимание в первую очередь?”. Отвечаю. Пожалуй, на всё. Наша жизнь состоит из мелочей и SEO-оптимизация тому не исключение. Практически невозможно сложить красивую картинку из пазла на 100 или даже 1000 элементов, если упустить часть деталей.  Поэтому остается только сосредоточиться, сесть за компьютер, поставить возле себя чашку ароматного кофе или чая, открывать чек-лист, кропотливо и внимательно анализировать проект по каждому из пунктов. В результате Вы получите полноценный труд в виде технического задания, которое, с большой вероятностью, Вам самим понравится и после внедрения обеспечит эффективное дальнейшее SEO-продвижение. Но, несмотря на важность всех мелочей и нюансов, я подготовил материал, в котором выделю 5 моментов критической важности, то, без чего достигнуть крепких ТОПов и заполучить целевой трафик невозможно, с кратким комментарием по их решению. Плюс все будет лаконично и конструктивно, ведь вычитать «простынь» под силу не каждому :) Наших 5 железных факторов 1. Семантика&Структура Моментом №1 в SEO анализе и оптимизации является тот, насколько структура сайта позволяет его продвигать.  Довольно часто возникает такая ситуация, что клиент хочет или требует оптимизацию сайта под семантику, к которой сайт совершенно не готов структурно. На сайте может не быть нужной вложенности, категорий и подкатегорий, страниц отзывов и прайсов, без которых эффективной оптимизации под интересную для клиента семантику не получится. Поэтому, крайне важно параллельно выбирать и анализировать семантику, а также давать рекомендации и правки по структуре сайта. Семантика + структура - очень серьезная связка. Лучше согласовать и внедрить все моменты на берегу, чем когда Вы уже выйдете в открытое плаванье и придется грести веслами обратно. Но также важно помнить, что не любая семантика, которую предлагает или на которой настаивает клиент является правильной. В силу незнания он может быть убежден в одном, но в реальности дела могут обстоять иначе. Нивелируйте это своим погружением в бизнес и опытом. 2. Настройка карты сайта, ЧПУ и хлебных крошек. Если на предыдущем этапе все ОК, двигаемся дальше. Думаю, каждому из нас хоть раз приходилось заблудиться на улице. В этом случае так хочется у первого встречного прохожого здесь и сейчас получить толковую консультацию, как попасть на улицу, которую мы ищем. А если мы еще и торопимся на жизненно важную встречу, то градус ситуации накален вдвойне. Шучу) К чему все это? Правильная навигация важна и для поисковых роботов. Он не будет тратить время на то, чтобы сканировать страницы с непонятным назначением, уровнем вложенности и неизвестной глубины. Ему необходимо видеть эту структуру и навигацию. Поэтому на сайте обязательно должны быть настроены: Человекопонятные url-адреса ЧПУ Все url-адреса на сайте должны быть приведены к ЧПУ-виду и иметь вид http://url/. Кириллица должна трансформироваться в латиницу. В качестве разделителя слов в ЧПУ следует использовать дефис "-". Также будет неоспоримым плюсом, если в url-адресах будет соблюдаться полная вложенность, т.е. http://url/>/. Пример не ЧПУ адреса может выглядеть так: site.domain/index.php?id=75. Примером ЧПУ адреса для этой же страницы может быть site.domain/itvdn. После настройки ЧПУ следует также сделать 301 редирект с не-ЧПУ урлов на ЧПУ. В нашем случае это 301 редирект с site.domain/index.php?id=75 на site.domain/itvdn. Настройка ЧПУшек и соответствующих редиректов, как правило, решается подключением стандартных плагинов. Если речь идет о самописной системе, скорее всего нужно будет «допиливать» соответствующий функционал. Реализация «хлебных крошек» Breadcrumbs Под «хлебными крошками» подразумевается навигационная цепочка, которая отражает вложенность структуры и чаще всего располагается над или под основным текстовым заголовком страницы.     Реализация Breadcrumbs полезна не только для того, чтобы показать поисковику глубину структуры сайта, но и с точки зрения юзабилити. Посетителю будет всегда удобно выйти на уровень или два уровня выше, допустим в каталог, если со страницей товара он полностью ознакомился, но хочет посмотреть что-то еще. Карта сайта sitemap.xml Как правило, данные карты генерируются стандартными плагинами в зависимости от того, на какой CMS сделан сайт. Либо есть универсальные решения, например, специальная CMS для генерации карт, которая интегрируется в корень сайта и парсит всю его структуру, в результате чего и генерируется карта сайта. Адрес, по которому должна быть доступна карта, желательно делать site.domain/sitemap.xml. Но и это еще не все. Необходимо после генерации карты скормить ее поисковому роботу в GWT в разделе «Файлы Sitemap».     Если с содержанием карты будет что-то не в порядке, Вы увидите соответствующие предупреждения об этом, которые потребуется исправить. Хочу еще подчеркнуть, что генерация карты сайта происходит в самом конце внедрения ТЗ оп оптимизации, когда устранены дубли, настроены правильные ЧПУ и т.д.   3. Диагностика и устранение дублей. Дубли – это откровенное зло. Было бы Вам приятно, чтобы кто-то копировал Ваше поведение, одевался также, носил идентичную стрижку? Думаю, что вряд ли. И поисковые роботы в этом молодцы. Они такое рубят, занижают рейтинг целевых страниц и сайта в целом, если в его содержимом содержатся дубли. Каким образом их диагностировать? Для этого есть несколько методов. Самый простой - это воспользоваться данными по повторяющимся метатегам в разделе «Оптимизация HTML». Если дубли присутствуют, Вы увидите данные в таком виде:     Диагностировать дубли можно и с помощью программы NetpeakSpider. Такой вариант даже лучше в том плане, что он сканирует актуальную структуру сайта, а страницы в GWT сканируются периодически и информация может быть не первой свежести на момент, когда Вы ищите дубли. Дальше сам собой напрашивается вопрос о том, как нам избавиться от них. Если дубль полный, т.е является 100% клоном страницы, которую дублирует, стоит проставить 301 редирект с дубля на основную страницу и отправить данный дубль на принудительную переиндексацию в разделе «Просмотреть как Googlebot».     Существуют и другие методы борьбы с полными дубликатами, например, закрытие их в robots.txt и принудительное удаление через GWT. Но 301 редиректы считаются наиболее эффективным и правильным методом. В случае частичных дублей, например, когда дублируется только и/или и/или заголовки необходимо переписывать метатеги на дублях вручную, если их много, либо формировать и внедрять шаблоны метатегов, которые в результате генерации будут уникальными для каждой страницы. Пример шаблона автогенерации метатегов может выглядеть, например, так:       После активной борьбы по искоренению дублей Вы в идеале сорвете джек-пот в таком виде:     Резюмируя данный пункт, предлагаю раз и навсегда сказать «Нет!» дублям, вовремя проверять их и давать отпор! Едем дальше…   4. Борьба с аффилиатами Под аффилиатами подразумевается другой сайт клиента с такими же контактными данными, названием компании, структурой и тематикой. Поисковые системы “за естественную конкуренцию” и ведут борьбу с монополизацией рынка. Поэтому, склеивают аффилиаты, накладывая фильтры и занижая рейтинг сразу всех сайтов. По статистике 2 из 3 клиентов приходят к нам с аффилиатами. В их качестве зачастую выступают не самостоятельные сайты на отдельных CMS и доменах, а  площадки, сгенерированные на платформах типа Prom.ua или Allbiz. Это плохая практика и что в таком случае требуется делать? Алгоритм простой: Аргументируем клиенту всю ситуацию, запрашиваем доступы к аффилиатам, проверяем их. Добавляем каждый аффилиат в Google Webmaster Tools. Настраиваем 301 редиректы со всех страниц аффилиатов на главную страницу основного сайта. Отправляем на принудительную переиндексацию аффилиаты. Если нет возможности проставить 301 редирект, нужно воспользоваться опцией в GWT в разделе «Удалить URL-адреса».     Если внутри платформы нет возможности добавить сайт в панель вебмастеров (а такое случается часто), нужно просто согласовывать полное удаление сайта-аффилиата и ждать, когда он выпадет из индекса. Такой простой алгоритм действий позволил нам вывести не один сайт из-под фильтра. Вот один из кейсов нашей компании, где мы непосредственно применяли данную методику и вытащили сайт с самого дна поиска на первые позиции. Также бытует мнение, что достаточно изменить название компании, контактную информацию - и ситуация может измениться. Этот метод не работает. Не тратьте даже время на покупку новых телефонов и не ломайте голову, как бы себя по-новому еще назвать.   5. On-Page оптимизация Подразумевает заточку и оптимизацию конкретных целевых страниц под семантическое ядро.  Здесь важны следующие моменты: Написание и размещение оптимизированных метатегов. Подготовка и размещение полезного структурированного качественного текстового контента, при этом оптимизированного под нужные поисковые запросы. Помимо контента текстового следует использовать качественные (желательно “не тяжелые” по объему памяти) изображения на всю ширину страницы. Это еще в тренде. Не помешают также тематические видеоролики, которые точно повлияют на поведенческие факторы ПФ (снизят показатели отказов и увеличат время нахождения пользователя на странице). И многие другие интересные вещи, которые Вы узнаете дальше.   На десерт Как я и обещал в начале данной статьи, Вас ожидает сюрприз. Под этой статьей находится pdf-файл «Полный чек-лист seo-оптимизатора от Abweb». Запомните, что только титаническая работа позволит получить что-то стоящее не только в сфере SEO. Жду Ваших комментариев, до следующих публикаций! Полный чек-лист seo-оптимизатора от Abweb
Робота з посиланнями у HTML & CSS

Автор: Редакція ITVDN

Введение Буквы «H» и «T» в слове «HTML» означают «hypertext» – по сути, систему связанного текста. DOCTYPE html> <html> <head>     <title>My first web pagetitle> head> <body>     <h1>My first web pageh1>     <h2>What this ish2>     <p>A simple page put together using HTMLp>     <h2>Why this ish2>     <p>To learn HTMLp>     <h2>Where to find the tutorialh2>     <p><a href="http://www.htmldog.com">HTML Doga>p> body> html>   Атрибут href в тега <a> определяет адрес ссылки. Так если, например, Вы имеете другой файл "flyingmoss.html" в той же директории вашего проекта, то код будет следующим:  <a href="flyingmoss.html">The miracle of moss in flighta> С помощью ссылок также можно отправить пользователю часть той же страницы. Необходимо добавить атрибут id, например, <h2 id="moss">Mossh2>  и потом нужная ссылка будет такой: <a href="#moss">Go to mossa> Переходя по ней, пользователь перейдет на место в странице с указанным ID. Источник: http://www.htmldog.com/guides/html/beginner/links/
Робота з Touch в Unity3D

Автор: Олег Загородній

Введение Ни для кого не секрет, что в мобильных играх, в отличие от компьютерных, практически единственным “устройством ввода” является палец. То есть, все действия, которые пользователь выполняет в игре, совершаются благодаря прикосновениям к экрану, или же тачам (англ. touch – прикосновение). В этой статье мы с Вами рассмотрим, как можно правильно обработать тачи, разберем, в чем разница между глобальными и локальными тачами, а также реализуем обработку некоторых популярных жестов, которыми Вы оперируете не только в играх, но и в повседневном пользовании смартфоном – swipe и zoom. Разумеется, все это мы будем делать, используя исключительно встроенный функционал Unity3D, без внешних плагинов и ассетов. Наведем справки Перед тем, как начать, рассмотрим, какие возможности нам предоставляет библиотека для работы с тачами. В документации Unity видим, что разработчики движка рекомендуют использовать класс Input для получения доступа к данным об акселерометре и мульти-таче мобильного устройства. Это нас вполне устраивает. В обязательном порядке необходимо подключить пространство имен UnityEngine.EventSystems, ведь именно оттуда родом большинство интерфейсов и классов, которые нам сегодня понадобятся. Например, IPointerClickHandler, IDragHandler и многие другие. В конце концов, классы BaseEventData и PointerEventData, из которых мы будем доставать все необходимые данные о событиях, проживают по тому же адресу. Что ж, не стоит волноваться, если Вы видите эти имена впервые. Моя задача - сдружить вас и наставить на путь плодотворной разработки. Если у Вас уже имеется опыт работы с данными классами, надеюсь, смогу поведать о каких-либо интересных спецификах работы с ними и еще некоторыми компонентами. Ближе к делу  или “Что такое глобальные и локальные тачи?” Немного теории. Чтобы правильно реализовать все, что мы задумали, сначала разберемся, что такое глобальные и локальные тачи. Если вкратце, то глобальные тачи – это прикосновения к экрану устройства в любой точке. То есть, мы будем говорить, что необходимо обработать глобальный тач, если для игрового процесса не важно, где именно игрок ткнет пальцем в экран. Думаю, все видели в играх заставку после загрузки уровня с большими буквами “Tap to start” либо что-то в этом роде. Бывают настолько простые игры, что, по сути, все управление игроком производится исключительно такими вот глобальными тачами. Например, в Flappy Bird, 2 Cars и многих других. Разумеется, не всегда все так просто. Случается, нам необходимо обработать тач в определенной области экрана, или по какой-либо кнопке, или по объекту. Такие тачи мы с Вами будет именовать локальными, так как они должны производиться в некой локальной области. Причем принципы реализации обработки тачей по 2D объектам или же элементам UI и обработки тачей по 3D объектам на сцене немного отличаются. Эти нюансы мы также рассмотрим. То есть перед тем, как перейти к воплощению идеи в жизнь, хорошенько подумайте, где и какой вид тача будет использоваться, ведь от этого зависит, как далеко в лес мы пойдем и как много дровишек нарубим. Практика. Подготовим рабочее место, как на картинке. Также создадим новый скрипт HandleScript и прикрепим его на куб. Как же считать прикосновение к экрану? Если в случае с кликами мыши в классе Input есть методы GetMouseButton (...Up, ...Down), то для тачей соответствующие методы отсутствуют. Здесь все даже проще. Разработчики предоставляют свойство touchCount (только для чтения), в котором хранится количество тачей в текущем кадре. То есть, чтобы считать глобальный тач, нам необходима всего одна строчка в методе Update: using UnityEngine; using UnityEngine.EventSystems; public class HandleScript : MonoBehaviour { void Update () {      if (Input.touchCount > 0) Debug.Log("Global touch!"); } } Как только пользователь задумает ткнуть пальцем в экран (чего мы, по сути, и ждем), выражение в блоке условия вернет true и на консоль вылетит наше сообщение. Что может быть проще? Важно: проверить данный способ обработки на компьютере не получится, так как в свойство touchCount записывается именно кол-во тачей. Клики мыши не в счет. Примечание: К примеру, при портировании на Windows Phone сообщения консоли, разумеется, отображаться не будут. Так что стоит реакцию на тач сделать более явной. Допустим: if (Input.touchCount > 0) transform.localScale *= 1.1f; Я специально буду обращать Ваше внимание на многие нюансы (для кого-то известные и очевидные, а для кого-то - нет), чтобы избавить от мелких и неприятных ошибок и сберечь парочку нервных клеток. Попробуйте сбилдить на свой смартфон и немного потапать в разных частях экрана. Что касается локальных тачей, то здесь есть несколько вариантов обработки. Также они зависят и от типа  объекта – 2D или 3D. Начнем, пожалуй, с 2D объектов. Давайте добавим на сцену какой-либо спрайт и сразу прилепим ему компонент 2D Box Collider (о нем чуть ниже). Еще добавим к этому спрайту наш скрипт HandleScript, но немного его подкорректируем. В Unity есть перечень методов, которые являются обработчиками определенных событий. Например, метод OnCollisionEnter вызывается, когда два твердых (Rigidbody) объекта соприкасаются, если вкратце. Так вот, среди вышеупомянутого перечня методов есть такой себе OnMouseDown метод. Он вызывается, как вы уже, наверное, догадались, в момент нажатия левой кнопки мыши непосредственно на объекте. Здесь есть три важных момента: Метод вызывается непосредственно в момент нажатия кнопки, а не отпускания или полного клика. Метод реагирует только на левую кнопку мыши. Срабатывает только при клике непосредственно на объект. Так как мы с Вами обрабатываем тачи, а не клики, то справедливы для нас будут только первый и третий пункты. То есть работу с человеческими пальцами данный метод тоже поддерживает. А может, и не только человеческими... Как же будет выглядеть наш код? using UnityEngine; using UnityEngine.EventSystems; public class HandleScript : MonoBehaviour { void OnMouseDown() {      transform.localScale *= 1.1f; } } Обратите внимание на сигнатуру метода и запомните. Ведь если сделать малейшую опечатку, событие касания/клика обрабатываться не будет. Проверить работу этого способа уже проще. Учитывая, что метод OnMouseDown реагирует как на мышь, так и на пальцы, билдить проект на смартфон не обязательно. Из этой серии есть еще метод OnMouseUp, который вызывается при отпускании пальца/кнопки. Важно: все события, связанные с кликами, движок Unity считывает, неявно используя Raycast’ы (лучи). Именно поэтому мы добавили на наш спрайт компонент 2D Box Collider. Если Вы еще не знаете, в чем суть работы Raycast’ов, обязательно почитайте в документации Unity. Важно: получается, указанные методы срабатывают при тапе/клике именно по коллайдеру объекта, а не по мэшу(Mesh)/спрайту. Попробуйте сбилдить и потапать на спрайт ящика либо зеленого куба. Теперь отключите их коллайдеры и проверьте, обрабатывается ли событие. Как видите, этот способ позволяет обработать тап как по 2D, так и по 3D объекту. Просто? Следующий способ обработать локальный тач тоже работает для обоих типов объектов, но немного отличается конфигурацией компонентов. Здесь мы с Вами будем уже работать с таким пространством имен, как UnityEngine.EventSystems. Если оно у Вас еще не подключено, самое время это сделать. Там, как я уже говорил, находятся необходимые нам интерфейсы и классы. Теперь обязательно добавьте на сцену объект EventSystem. Он находится во вкладке UI контекстного меню создания объекта. Итак, чтобы считать тап по 2D объекту (не элементу UI), необходимо обязательно прикрепить к камере компонент Physics 2D Raycaster. Для данного компонента обязательным является присутствие компонента Camera. Поэтому совсем неудивительно, что мы цепляем его именно на объект Main Camera. То есть после всех наших манипуляций игровая сцена должна выглядеть, как на картинке. Теперь, пожалуй, в код. Данный метод более универсальный, чем предыдущий, так как позволяет получить множество информации о состоянии курсора. Неважно, кто им управляет – палец или мышь. Нам понадобится интерфейс IPointerDownHandler из подключенного пространства имен. После реализации единственного его метода, получаем код, не менее простой, чем раньше. using UnityEngine; using UnityEngine.EventSystems; public class HandleScript : MonoBehaviour, IPointerDownHandler { public void OnPointerDown(PointerEventData eventData) {      Debug.Log(eventData.position); } } Разумеется, ошибиться с сигнатурой метода у вас не выйдет, так как Visual Studio сразу ругнется за нереализованный интерфейс. А в параметре eventData типа PointerEventData будет храниться вся информация о курсоре на момент срабатывания метода, а это очень полезно. Что же будет происходить? Здесь тоже все просто. В момент касания движок Unity пустит луч в сцену и в случае, когда тот пройдет сквозь коллайдер нашего спрайта, сработает метод обработчик OnPointerDown и в параметр eventData запишется вся информация о курсоре. Для считывания тачей также есть следующие интерфейсы: IPointerUpHandler, IPointerClickHandler, IPointerEnterHandler и IPointerExitHandler. Мне кажется, по их именам предельно ясно, какой из них какое событие позволяет обработать. Все, что Вам необходимо – наследоваться от нужного интерфейса, реализовать единственный его абстрактный метод и удивиться, как просто это работает. Главное, когда будете работать, не забудьте о компоненте Physics 2D Raycaster и объекте EventSystem, которые упоминались выше. Как вы уже, наверное, заметили, на 3D объекты данный способ не распространяется. Как это исправить? Элементарно. На объект-камеру необходимо также прикрепить компонент Physics Raycaser. Вот и все. Остальная суть остается та же. Попробуйте запустить проект. Заметили? Движок реагирует на клики мыши тоже. Теперь портируйте на ваш смартфон и удостоверьтесь, что все работает верно. Чтобы обработать тачи по элементам UI, Вам необходим будет компонент Graphic Raycaster. Но для него обязательным является компонент Canvas. Это, думаю, тоже вполне логично. Если прикрепить его на объект Canvas, то методы рассмотренных нами интерфейсов позволят также обработать тачи по кнопкам, панелям, тогглам и т.д. Итог по разделу о глобальных и локальных тачах. Давайте немного подсуммируем все, что только что было рассмотрено. Все тачи и клики обрабатываются неявным пусканием лучей из экрана в сцену. То есть определяется касание к коллайдерам объектов. При использовании интерфейсов из пространства имен UnityEngine.EventSystems обязательно надо добавить объект EventSystem. Physics 2D Raycaster – компонент для обработки тачей/кликов по 2D объектам. Physics Raycaster – компонент для обработки тачей/кликов по 3D объектам. Graphic Raycaster – компонент для обработки тачей/кликов по элементам UI. В отличие от предыдущих присутствует на объекте Canvas по умолчанию. Обработка Swipe жестов Как же выловить эти Swipe жесты и как определить их направление? На самом деле, это совсем несложно. Есть несколько интерфейсов, которые позволят нам это сделать:    IDragHandler, IBeginDragHandler, IEndDragHandler. Причем, они отлично подходят как для работы с Drag, так и Swipe жестами. Давайте почистим нашу сцену и приведем ее примерно вот к такому виду: У нас на объекте Canvas есть красная панель размером на весь экран и внутри нее имеется еще одна небольшая панель. Мы с Вами будем считывать Swipe’ы по красной панели и в зависимости от их направления двигать зеленую. Все до безобразия просто. Аналогичные действия Вы потом сможете проделать не только с элементами UI, как в этом примере, но и с 2D и 3D объектами. Сейчас же будем использовать панели, так как это получится более наглядно. Скрипт HandlerScript прикрепляем к внешней (красной) панели. using UnityEngine; using UnityEngine.EventSystems; public class HandleScript : MonoBehaviour, IDragHandler, IBeginDragHandler { public void OnBeginDrag(PointerEventData eventData) { } public void OnDrag(PointerEventData eventData) {  } } Вот как изначально должен выглядеть наш скрипт. Мы должны наследоваться он интерфейсов IDragHandler и IBeginDragHandler. Этого будет достаточно, чтобы считать Swipe. Скажу даже больше. Мы будем использовать только метод из второго интерфейса. Важно: необходимо обязательно реализовать интерфейс IDragHandler (пусть даже методом с пустым телом), чтобы срабатывали методы из интерфейсов IBeginDragHandler и IEndDragHandler. Дабы определить направление Swipe’а, мы будет использовать свойство delta в параметре eventData метода OnBeginDrag. В это свойство записывается разница позиций курсора между текущим и предыдущим кадрами. Мы просто напросто в момент начала Swipe’а глянем, какое значение этой дельты, и из этого уже определим, какое направление жеста. Возможно, у Вас возник вопрос. Откуда возьмется эта дельта, если метод OnBeginDrag сработает сразу, как только игрок начнет вести пальцем по экрану? Дело вот в чем. Этот метод вызывается только после того, как игрок сдвинет палец на какое-то пороговое значение расстояния от начальной точки. За это время успевает накопиться некоторая информация о происшедшем событии. То есть за этот небольшой промежуток времени мы можем определить, куда пользователь собирается вести свой палец. Мы всего лишь должны построить правильную условную конструкцию для определения направления и, исходя из условия, двигать зеленую панель в соответствующем направлении. В будущем это может быть ваш игрок в раннере или что-либо иное... using UnityEngine; using UnityEngine.EventSystems; public class HandleScript : MonoBehaviour, IDragHandler, IBeginDragHandler { Transform green;   // здесь будет ссылка на компонент Transform зеленой панели. void Start() {      green = transform.GetChild(0); // получаем ссылку на Transform зеленой панели. } public void OnBeginDrag(PointerEventData eventData) {      if (Mathf.Abs(eventData.delta.x) > Mathf.Abs(eventData.delta.y))      {             if (eventData.delta.x > 0) Debug.Log("Right");             else Debug.Log("Left");             green.position += new Vector3(eventData.delta.x, 0, 0);      }      else      {             if (eventData.delta.y > 0) Debug.Log("Up");             else Debug.Log("Down");             green.position += new Vector3(0, eventData.delta.y, 0);      } } public void OnDrag(PointerEventData eventData) { } } Что мы сделали? Сначала проверили, дельта по какой оси больше – X или Y? Если по оси X, значит движение будет по горизонтали, если же по Y – значит, по вертикали. А там еще раз проверили направление. Как видите, это делается элементарно просто, а работает безотказно. Обязательно проверьте, обрабатывается ли жест Swipe у вас на смартфоне. Если же Вам необходимо получить непосредственно угол Swipe’а, можно использовать формулу , которая позволяет вычислить синус угла прямоугольного треугольника из отношения противоположной и прилегающей сторон. Обработка Zoom’а Вернем сцену к первоначальному состоянию. Чтобы считать жест zoom’а, нам необходимо обработать глобальные тачи, поэтому наш скрипт HandleScript можно прикрепить даже на камеру. А код наш будет выглядеть вот так: using UnityEngine; public class HandleScript : MonoBehaviour { public float sensitivity; Vector2 f0start; Vector2 f1start; void Update() {      if (Input.touchCount < 2)      {             f0start = Vector2.zero;             f1start = Vector2.zero;      }      if (Input.touchCount == 2) Zoom(); } void Zoom() {      if (f0start == Vector2.zero && f1start == Vector2.zero)      {             f0start = Input.GetTouch(0).position;             f1start = Input.GetTouch(1).position;      }      Vector2 f0position = Input.GetTouch(0).position;      Vector2 f1position = Input.GetTouch(1).position;      float dir = Mathf.Sign(Vector2.Distance(f1start, f0start) - Vector2.Distance(f0position, f1position));      transform.position = Vector3.MoveTowards(transform.position, transform.position + transform.forward, dir * sensitivity * Time.deltaTime * Vector3.Distance(f0position, f1position)); } } В чем суть его работы?  Если пользователь прикасается к экрану двумя пальцами, координаты двух тачей записываются в соответствующие поля f0start и f1start. Именно с ними будут сравниваться все остальные позиции тачей, пока игрок не уберет от экрана пальцы. То есть мы просто сравниваем расстояние между двумя тачами. Если текущее расстояние меньше, чем начальное, то камера будет двигаться назад, если же больше – вперед. Условная конструкция в методе Zoom для того, чтобы позиции тачей записались в свойства только один раз в момент касания к экрану. Чувствительность zoom’а вы можете регулировать значением поля sensitivity прямо в окне Inspector. Попробуйте усовершенствовать этот скрипт сами. Допустим, сделать, чтобы сравнивались позиции не текущих и начальных тачей, а позиции тачей в этом и предыдущем кадре. Сравните результат. Заключение Как видите, обработка тачей и рассмотренных нами жестов реализуется очень просто. Все, что Вам необходимо – внимательность и фантазия. Если что-то не работает, обязательно проверьте, присутствуют ли необходимые компоненты на всех объектах, вызываются ли нужные методы и так далее. Совсем не обязательно искать внешние библиотеки, плагины и ассеты для того, чтобы работать с тачами в Unity. Разработчики предоставляют, по сути, всё, что вам может понадобится. Результат же зависит от Вашей фантазии. Не забывайте заглядывать в документацию Unity, там есть много всего интересного. Хотя, среди того, что мы сегодня рассмотрели, есть  вещи, о которых там не упоминают. Благодарю за внимание и желаю всем творческих успехов!
Робота з текстом: Адреси, Визначення, 2-спрямованість та редагування

Автор: Редакція ITVDN

Введение Должно быть, Вы уже знаете, что существует огромное количество текстовых тегов. Вы знакомы с параграфами, заголовками и даже аббревиатурами. Но существует множество других, более непонятных и сложных тегов. Непонятных, потому что вы вряд ли найдете их в интернете, и не потому что они не нужны. Если Вы найдете текст с объяснениями, то используйте новые для себя элементы для создания более качественного, лучшего, более значимой HTML-страницы. Адреса Тег address используется специально для контактных данных или всей веб-страницы (единожды). Это не значит, что address нужно обязательно применять для всех старых адресов. <h3>Author contact detailsh3> <address> <ul> <li>0123-456-7890li> <li>author_dude@noplaceinteresting.comli> <li>http://www.noplaceinteresting.com/contactme/li> ul> address> Определения Тег dfn используется для выделения первого термина. Как и тег abbr, атрибут title может быть использован для описания термина. <p>Bob's <dfn title="Dog">caninedfn> mother and <dfn title="Horse">equinedfn> father sat him down and carefully explained that he was an <dfn title="A mutation that combines two or more sets of chromosomes from different species">allopolyploiddfn> organism.p> Двунаправленный текст Тег bdo может использовать обратное направление текста, следовательно, может отображать языки, что читаются справа налево. Атрибут dir может принимать значения ltr (слева направо) или rtl (справа налево). <bdo dir="rtl">god lmthbdo> Редакции Теги ins и del используются для отображения соответственно вставленных и удаленных частей. Они не имеют ограничений применения в тексте, также могут быть применены для целых разделов контента и, как правило, используются в «Track Changes» - дословно «отслеживание изменений». Теги редакции также имеют атрибуты datetime, чтобы показать, когда была произведена правка, а также cite – причины изменений. <p>I have decided to <del datetime="2013-01-26">decreasedel><ins cite="http://www.icecreamforall.com/changeofpolicy/">increaseins> the amount of free ice cream that the State will provide for its citizens.p> Как и в обычных текстовых редакторах, элемент ins применяют для подчеркивания текста, а для зачеркивания – del. Источник: http://www.htmldog.com/guides/html/intermediate/text2/
Framework у С# для перевірки відбитків пальців

Автор: Редакція ITVDN

Введение В наше время распознавание отпечатков пальцев является активным направлением исследований. Важным компонентом в системе распознавания отпечатков является алгоритм. В связи с проблемой данной сферы алгоритмы распознавания отпечатков пальцев делятся на две категории: алгоритмы проверки и идентификации. Цель алгоритмов проверки отпечатков пальцев является – определить, какой из двух отпечатков сделан одним пальцем, а какой нет. С другой стороны, алгоритмы идентификации делают поиск запроса отпечатка пальца в базе данных, ища отпечаток, сделанный одним и тем же пальцем. Насколько мы знаем, существуют сотни документов, касающихся проверки отпечатков пальцев, но нет ни одного фреймворка, позволяющего проверять отпечатки в сети. Поэтому вы должны осуществлять ваши личные настройки, тестировать выполнения алгоритмов распознавания ваших отпечатков. Более того, вы должны потратить много времени, выполняя алгоритмы других авторов, для сравнения с собственными. FVC-onGoing – наиболее связанный с работой нашего фреймворка в веб-системе. Данная система имеет такие ограничения: У вас нет доступа к другим алгоритмам, кроме своих. Это не фреймворк, поэтому вы не можете использовать другие компоненты программного обеспечения. Система не может быть использована с целью обучения, так как ученик не может посмотреть, как работают алгоритмы. После выполнения опыта используется база данных (стандартная или жесткая), вам необходимо ждать 30 дней для, того чтобы сделать следующий эксперимент, используя ту же базу данных. Вы не можете управлять базой данных. Таким образом, вы не можете использовать собственную базу данных либо редактировать существующую. Отсутствует доступ к тем отпечаткам, для которых ваш алгоритм не выполнился. Следовательно, вы не сможете проанализировать, почему ваш алгоритм не выполнился для того, чтобы исправить код. Вы не сможете создать эксперимент с помощью обычного протокола, для оценки выполнения Если в любом из указанных выше ограничениях для вас возникли проблемы, тогда используйте наш фреймворк. Наш фреймворк реализован на С# с использованием .Net Framework по двум главным причинам. Во-первых, С# стал одним из самых популярных языков программирования. Вторая причина в том, что инструменты, библиотеки и классы, доступные в .Net Framework, экономят много времени написания кода. Наш фреймворк позволяет экспериментировать в базах данных типа B от FVC2000, FVC2002 и FVC2004, и в базах данных типа А от FVC2002 и FVC2004. В этих экспериментах мы выполняем индикаторы the Fingerprint Verification Competitions (EER(%), FMR100(%), FMR1000(%), ZeroFMR(%), Time(ms) и ROC curves).  Кроме того, вы можете делать опыты даже с обычным протоколом и разными базами данных. Мы реализовали алгоритмы распознавания отпечатков пальцев, предложенный Tico и Kuosmanen, Jiang и Yau, Medina-Pérez и Qi. Важно обратить внимание на то, что вопреки алгоритму Qi - это набор шаблонов отпечатков пальцев, основывающийся на алгоритмах, мы реализовали только алгоритмы, сопоставимые протоколами ввода отпечатка пальца. Мы также сделали алгоритмы выделения признаков, предложенный Ratha, и ориентацию на получение изображения предложенную Sherlock. Данный фреймворк позволяет вам добавлять, как новые алгоритмы распознавания отпечатков, так и новые алгоритмы выделения признаков с минимальными усилиями и без перекомпиляции фреймворка. Одна из целей, которую мы преследовали, когда разрабатывали данный фреймворк, была сделать классы интерфейсов простыми и доступными. Таким образом, процесс добавления новых алгоритмов очень прост. В этой статье мы вкратце объясняем, как: экспериментировать над распознаванием отпечатков пальцев; увидеть шаблон отпечатка пальца после выполнения алгоритма; высчитать и вывести на дисплей отпечаток пальца; интегрировать ваши алгоритмы в фреймворк. Расширения данного фреймворка с целью исследований появились в https://sites.google.com/site/miguelmedinaperez/software/fprframework В данной статьей мы вкладываем следующие файлы: FingerprintRecognition_v2.2.zip: исходные файлы нашего фреймворка. Help.zip: Исходный код документации. Запуск исследования для распознавания отпечатков пальцев Извлеките файл “FingerprintRecognition.zip” и постройте решение. Далее вы можете отлаживать проект “FR.FVCExperimenter” или можете запустить “FR.FVCExperimenter.exe” в директорию, которая содержит сгенерированный узел. Данное окно откроет: В строке “Resources” записан путь к базе данных, которую вы собираетесь использовать, к примеру: “D:\PR Databases\Fingerprints\FVC2004\DB1_B”. Выберите подходящий вам тип опыта в всплывающем меню с названием “Experiment”. Используйте меню с названиями “Minutia Extractor”, “Orientation Image Extractor” и “Skeleton Image Extractor“ для выбора алгоритма, который будет использоваться для нахождения основных особенностей (отпечаток, ориентированное изображение и его образ). Используйте поле “Matcher” для выбора алгоритма распознавания отпечатков пальцев и поле “Feature Provider” для выбора алгоритма, который будет хранить и извлекать черты выбранных совпадений. Несмотря на то, что мы реализовали только одну черту распознавания для каждого совпадения, существуют сценарии, где вы используете несколько признаков для одного совпадения. Поле с названием “Properties” позволяет изменять параметры выбранного алгоритма. Кликните на кнопку “Execute Experiment” для запуска исследования. Данный опыт использует протокол оценки от the Fingerprint Verification Competitions. В этом опыте мы высчитали такие индикаторы: EER(%), FMR100(%), FMR1000(%), ZeroFMR(%), Время(мс) и  ROC-кривая. Эти индикаторы сохранены в файле с именем, сформированным в зависимости от выбранного вами алгоритма и окончанием ".Summary.csv". Этот файл сохраняется в папке с названием "Results" в той же папке, где хранятся отпечатки пальцев. Также сохранены еще два файла, один хранит в себе ложные соответствия отпечатков пальцев, другой – ложные несоответствия отпечатков. Если вы хотите сравнить 2 отпечатка и проверить их совпадение, кликните на кнопку “Visual Match”, после которой откроется форма “Visual Fingerprint Matching”. Загрузите отпечатки, которые вы хотите сравнить и нажмите кнопку “Match”. Экстрактор признаков и выбранный в “FVC Experimenter” режим также здесь используются для того, чтобы выполнить сравнение отпечатков пальцев. Ниже пример сравнения двух отпечатков. Визуализация очертаний отпечатка пальца Если вы хотите вывести картинку очертания отпечатка, тогда вам нужно использовать проект “FR.FeatureDisplay”. В поле “Fingerprint Feature Display” вы можете изменять экстрактор признаков и их изображение. В фреймворке мы используем классы для визуализации отпечатка, ориентированное изображение и скелет картинки. В следующем примере вы можете увидеть визуализацию приблизительного изображения отпечатка: Соответствие отпечатков вне фреймворка В данном разделе представлен пример использования фреймворка для сравнения двух изображений отпечатков в обычном пользовательском приложении. Он складывается из 3 шагов для сравнения 2 изображений отпечатков: загрузить картинку, извлечение признаков и их сравнение. В этом случае пользователям нужно добавить ссылки из их приложения к сборке FR.Core и FR.Medina2012. Сборки SHullDelaunayTriangulation и ImageProcessingTools должны быть добавлены в папку вывода, где появится бинарный файл. // Loading fingerprints var fingerprintImg1 = ImageLoader.LoadImage(fileName1); var fingerprintImg2 = ImageLoader.LoadImage(fileName2); // Building feature extractor and extracting features var featExtractor = new MTripletsExtractor() { MtiaExtractor = new Ratha1995MinutiaeExtractor() }; var features1 = featExtractor.ExtractFeatures(fingerprintImg1); var features2 = featExtractor.ExtractFeatures(fingerprintImg2); // Building matcher and matching var matcher = new M3gl(); double similarity = matcher.Match(features1, features2); Пример использования M3gl  показывает, как легко использовать фреймворк, и как хорошо сложен и не требует пояснений код. Правила хорошего дизайна применены в фреймворке и дают возможность пользователю легко заменить или изменить любой компонент. Добавление новых алгоритмов в фреймворк Первое, что вы должны знать - это то, что вам не нужно модифицировать приложение фреймворка для распознавания собственных алгоритмов, потому что мы используем Рефлекцию, для того чтобы загрузить все динамические алгоритмы во время выполнения. Вы можете создать столько приложений, сколько хотите в директории, которая содержит фреймворк. Для каждого нового приложения зайдите в настройки и укажите путь вывода со значением “..\bin\Release\”. Для добавления новой функции определения вам нужно наследовать с базового класса FeatureExtractor и реализовать метод ExtractFeatures(Bitmap image). Например, предположим, что вы хотите создать функцию определения типа MyFeature, дальше вы можете реализовать класс по примеру:  public class MyFeatureExtractor : FeatureExtractor {     public override MyFeature ExtractFeatures(Bitmap image)     {         // Place here your code to extract features     } } В случае, если новая функция была построена на некоторых существующих, вы можете поступить следующим образом: public class MyFeatureExtractor : FeatureExtractor {     public FeatureExtractor<List> MtiaExtractor { set; get; }     public FeatureExtractor OrImgExtractor { set; get; }     public override MyFeature ExtractFeatures(Bitmap image)     {         try         {             var mtiae = MtiaExtractor.ExtractFeatures(image);             var orImg = OrImgExtractor.ExtractFeatures(image);             return ExtractFeatures(mtiae, orImg);         }         catch (Exception e)         {             if (MtiaExtractor == null)                 throw new InvalidOperationException("Cannot extract MyFeature: Unassigned minutia list extractor!", e);             if (OrImgExtractor == null)                 throw new InvalidOperationException("Cannot extract MyFeature: Unassigned orientation image extractor!", e);             throw;         }     }     public MyFeature ExtractFeatures(List mtiae, OrientationImage orImg)     {         // Place here your code to extract features     } } Для каждой функции определения вы должны создать поставщик ресурса. Поставщик ресурса позволяет сохранять (полученный) в (выходной) файл ресурс, связанный с отпечатком. Фреймворк включает в себя поставщик ресурса для извлекания отпечатков (MinutiaListProvider), ориентированное изображение (OrientationImageProvider) и скелет картинки (SkeletonImageProvider). В следующем примере поставщика ресурсов для функции извлекания определены ниже. public class MyFeatureProvider : ResourceProvider {     public MinutiaListProvider MtiaListProvider { get; set; }     public OrientationImageProvider OrImgProvider { get; set; }     public override string GetSignature()     {         return "myf";     }     public override bool IsResourcePersistent()     {         return true;     }     protected override MyFeature Extract(string fingerprint, ResourceRepository repository)     {         try         {             var mtiae = MtiaListProvider.GetResource(fingerprint, repository);             var orImg = OrImgProvider.GetResource(fingerprint, repository);             return featureExtractor.ExtractFeatures(mtiae, orImg);         }         catch (Exception e)         {             if (MtiaListProvider == null)                 throw new InvalidOperationException("Unable to extract MyFeature: Unassigned minutia list provider!", e);             if (OrImgProvider == null)                 throw new InvalidOperationException("Unable to extract MyFeature: Unassigned orientation image provider!", e);             throw;         }     }     private MyFeatureExtractor featureExtractor = new MyFeatureExtractor(); } Пришло время создать новый алгоритм совпадения отпечатков пальцев. Предположим, вы хотите сравнить функции типа MyFeature, для этого вам необходимо создать «сравнитель» такой как: public class MyMatcher : Matcher {     public override double Match(MyFeature query, MyFeature template)     {         // Place here your code to match fingerprints     } } В случае, если вы реализовали алгоритм сравнения отпечатков, дальше вам необходимо изменить в коде ниже следующее: public class MyMatcher : Matcher, IMinutiaMatcher {     public override double Match(MyFeature query, MyFeature template)     {         List matchingMtiae;         return Match(query, template, out matchingMtiae);     }     public double Match(object query, object template, out List matchingMtiae)     {         // Place here your code to match fingerprints     } } Интегрированные встроенные алгоритмы в фреймворке Пользователям не нужно изменять фреймворк для интеграции обычных алгоритмов, так как Рефлекция загружает динамически, во время выполнения программы. В этом случае пользователи должны добавить новые алгоритмы к их собственным обычным сборкам. Для того, чтобы использовать существующие алгоритмы сравнения в фреймворке, первое, что необходимо сделать, создать поставщик ресурсов. Поставщик ресурсов позволяет сохранять (полученный) в (выходной) файл ресурсы, связанные с отпечатками пальцев. К примеру, предположим, что пользователи хотят интегрировать SourceAFIS SDK (http://www.sourceafis.org/) в фреймворк, следующая функция обеспечения может использоваться как: public class SourceAFISFeatureProvider : ResourceProvider {     protected override Person Extract(string fingerprint, ResourceRepository repository)     {         Fingerprint fp = new Fingerprint();         fp.AsBitmap = imageProvider.GetResource(fingerprint, repository);         Person person = new Person();         person.Fingerprints.Add(fp);         Afis.Extract(person);         return person;     }     public override string GetSignature()     {         return string.Format("sAFIS");     }     public override bool IsResourcePersistent()     {         return true;     }     private static AfisEngine Afis = new AfisEngine(); } А сейчас алгоритм сравнения отпечатков может быть записан в следующие классы: public class SourceAFISMatcher : Matcher {     public override double Match(Person query, Person template)     {         return Afis.Verify(query, template);     }     private static AfisEngine Afis = new AfisEngine(); } Результаты эксперимента Мы выполнили обширный эксперимент с алгоритмами сравнения отпечатков пальцев, пользуясь фреймворком. Выводы В данной статье продемонстрировали фреймворк в C# для распознавания отпечатков пальцев. Мы коротко объяснили, как выполнить опыты по распознаванию отпечатков и как интегрировать собственные алгоритмы в фреймворк. Мы предоставили несколько алгоритмов сравнения отпечатков пальцев и алгоритмов извлечения признаков, с помощью которых вы можете не только делать эксперименты, но и создать собственные приложения. Мы показали исходные коды всех алгоритмов, поэтому пользователь может использовать любую часть кода так же, как и любой компонент программного обеспечения. Источник: http://www.codeproject.com/Articles/97590/A-Framework-in-C-for-Fingerprint-Verification
Модуль Asyncio Python

Автор: Олексій Орленко

Введение Мы продолжаем цикл статей об асинхронном программировании с использованием сопрограмм в Python. В предыдущей статье мы рассмотрели реализацию сопрограмм при помощи генераторов в Python 2.5 и выше, в этой же познакомимся с той инфраструктурой, которая построена на основе них в Python 3. В Python 3.4 был включён модуль asyncio, который, на самом деле, был доступен в виде отдельного пакета на PyPI ещё для Python 3.3. Этот модуль предоставляет всю необходимую инфраструктуру для написания однопоточного конкурентного кода с использованием сопрограмм неблокирующего ввода-вывода, мультиплексирования ввода-вывода через сокеты и другие ресурсы, запуска сетевых клиентов и серверов и т.д. Его возможности: цикл событий с разными его реализациями, оптимизированными для различных операционных систем; абстракции «транспорта» и «протокола» (подобные тем, что используются в фреймворке Twisted); поддержка TCP, UDP, SSL, конвейеров UNIX-процессов, отложенных вызовов; адаптированный для использования с циклом событий класс Future, который представляет ещё не вычисленный результат асинхронной функции; сопрограммы и задачи, основанные на основе генераторов; поддержка отмены Future и сопрограмм; примитивы синхронизации для использования с сопрограммами; возможность запуска задач в пуле потоков либо пуле процессов, что позволяет даже взаимодействовать с библиотеками, которые совершают блокирующий ввод-вывод. В основе модуля asyncio лежит цикл событий (event loop). Он отвечает за: создание задач из сопрограмм и Future и их выполнение; регистрацию, исполнение и отмену отложенных вызовов; создание клиентских и серверных транспортов для различных видов коммуникации; запуск подпроцессов и связи их с транспортами для взаимодействия со внешним процессом; делегирование медленных вызовов обычных функций пулу потоков или пулу процессов. Сопрограммы в asyncio – это генераторы, которые отвечают определённым требованиям. Ко всем сопрограммам должен быть применён декоратор @asyncio.coroutine. Действия, которые поддерживают сопрограммы asyncio: result = yield from future – приостановка выполнения сопрограммы до получения future значения и присвоение этого значения переменной result (если future отменён, возникает исключение CancelledError); result = yield from coroutine – ожидание завершения работы другой сопрограммы и получение её результата; return result – возврат значения в сопрограмму, ожидающую данную; raise exception – выброс исключения для обработки его ожидающей сопрограммой (если оно не обработано в текущей). Рассмотрим пример двух сопрограмм, одна из которых вызывает другую, производящую какие-то затратные вычисления (на самом деле, для простоты примера она будет просто приостанавливать своё выполнение на одну секунду и возвращать квадрат числа). import asyncio @asyncio.coroutine def time_consuming_computation(x):     print('Computing {0} ** 2...'.format(x))     yield from asyncio.sleep(1)     return x ** 2 @asyncio.coroutine def process_data(x):     result = yield from time_consuming_computation(x)     print('{0} ** 2 = {1}'.format(x, result)) if __name__ == '__main__':     loop = asyncio.get_event_loop()     loop.run_until_complete(process_data(238))     loop.close() Функция get_event_loop модуля asyncio возвращает объект цикла событий, и мы используем его метод run_until_complete для запуска сопрограммы. Какое же в данном случае преимущество перед обыкновенными функциями? Во время работы сопрограммы asyncio.sleep выполнение программы не блокируется, и, если бы у нас были другие запланированные для выполнения задачи, они могли бы в это время выполняться в том же самом потоке. Несмотря на то, что данные сопрограммы выглядят как обычный последовательный код, на самом деле отдельные их части исполняются асинхронно. На схеме выше показано, в каком порядке исполняется код из примера. Можем переписать созданный ранее пример при помощи модуля asyncio. import asyncio import random import time @asyncio.coroutine def consume():     """Сопрограмма обработки данных"""     running_sum = 0     count = 0     while True:         data = yield from produce()         running_sum += data         count += 1         print('Got data: {}\nTotal count: {}\nAverage: {}\n'.format(             data, count, running_sum / count)) @asyncio.coroutine def produce():     """Сопрограмма выдачи данных."""     yield from asyncio.sleep(0.5)     data = random.randint(0, 100)     return data def main():     loop = asyncio.get_event_loop()     loop.run_until_complete(consume())     loop.close() if __name__ == '__main__':     main()   Обратите внимание, что пришлось изменить логику его работы: теперь основной является сопрограмма consumer, а producer выдаёт одну порцию данных. Причиной этого является рассмотренные ранее ограничения, накладываемые на сопрограммы asyncio, которые логично следуют из основного предназначения данного модуля: совершение асинхронного ввода-вывода. В более реальном примере аналог сопрограммы producer мог бы, например, получать данные с внешнего сервера или базы данных.
Async/Await: Герой, якого JavaScript заслужив

Автор: Редакція ITVDN

Введение Написание асинхронного кода – задача не из легких. Когда дело доходит до JavaScript, мы в значительной мере полагаемся на функции обратного вызова для выполнения асинхронных задач, которые могут быть недостаточно интуитивными. Это создает некоторый барьер входа для новичков в программировании на JavaScript и вызывает частые проблемы у тех, кто уже пользовался языком некоторое время. В этой статье мы исследуем, как можно использовать предложение для ECMAScript 2016 (ES7) для усовершенствования опыта асинхронного программирования на JavaScript, чтобы сделать наш код более понятным и простым в написании. Мир сегодняшнего дня Давайте начнем с рассмотрения попытки асинхронного программирования. Следующий пример использует библиотеку запросов, чтобы сделать http-запрос к the Ron Swanson Quotes API и выведет ответ на консоли. Чтобы это сработало, нужно вставить следующий файл с именем app.js и запустить npm install request для установления зависимости. Если у Вас не установлен Node.js, можете скачать его отсюда. var request = require('request'); function getQuote() {     var quote;     request('http://ron-swanson-quotes.herokuapp.com/quotes', function (error, response, body) {         quote = body;     });     return quote; } function main() {     var quote = getQuote();     console.log(quote); } main(); Почему это происходит? Причина того, что цитата переменной неопределенна, в том, что функция обратной связи не вызывается до тех пор, пока не закончится функция запроса. Но так как функция запроса выполняется асинхронно, JavaScript не ждет завершения. Вместо этого он переходит к следующему оператору, который возвращает неопределенную переменную. Для лучшего объяснения того, как JavaScript работает «под капотом», просмотрите эту интересную беседу Филипа Робертса на JSConf EU. Синхронный код, как правило, легче понять и написать, потому что все выполняется в том порядке, в котором оно написано. Возвращаемые значения имеют широкое применение и довольно интуитивны на других языках, но, к сожалению, мы не можем использовать их так часто, как  мы бы хотели в JavaScript, так как они не работают с его асинхронной природой. Так зачем идти по пути асинхронного кодирования? Представьте, что сетевые запросы и чтение с диска являются тем, что мы называем операциями ввода/вывода (I/O input/output). В синхронном I/O исполнении программа блокируется и ждет передачи данных для завершения. Если это занимает 60 секунд для того, чтобы обратиться к базе данных для завершения, то программа ждет, ничего не делая, в течение 60 секунд. Однако, во время выполнения асинхронной I/O операции, программа может возобновить нормальное выполнение и иметь дело с результатами I/O операции, когда бы они ни поступили. Поэтому и существуют функции обратного вызова, но с обратными вызовами гораздо труднее работать и понимать при чтении источника приложения. Утопия Можем ли мы получить лучшее из обоих миров – асинхронный код, который позволяет нам работать с блокированными операциями, но также простой в чтении и написании, как синхронный. Ответ – да. Благодаря предложению ES7 для асинхронных функций (Async/Await). Когда функция декларирована как асинхронная, тогда она в состоянии обеспечить выполнение вызываемого кода, пока он ожидает  решения promise. Вы можете заменить код в app.js следующим. Мы также должны установить Babel  для запуска. Сделайте это с помощью npm install babel. Babel будет преобразовывать наш код ES7 в более работоспособную современную версию.  var request = require('request'); function getQuote() {     var quote;     return new Promise(function(resolve, reject) {         request('http://ron-swanson-quotes.herokuapp.com/quotes', function(error, response, body) {             quote = body;             resolve(quote);         });     }); } async function main() {     var quote = await getQuote();     console.log(quote); } main(); console.log('Ron once said,'); Можно видеть, что мы возвращаем promise, что оборачивает сетевой запрос внутри нашей getQuote функции. Внутри функции обратного вызова, переданной запросу, мы вызываем функцию решения promise с телом результата. Выполните следующее, чтобы запустить этот пример. ./node_modules/.bin/babel-node app.js // Ron once said, // {"quote":"Breakfast food can serve many purposes."} Этот код выглядит довольно круто и близок к оригинальной попытке. Он выглядит довольно синхронным, хотя это не так. В случае, если Вы не заметили, «Ron once said» был напечатан первым, несмотря на то, что вызывается после main. Это показывает, что мы не блокируем работу, пока ожидаем завершения запроса сети. Внесение улучшений Мы можем и дальше улучшить код, добавляя обработку ошибок с блоком try/catch. Если существует ошибка во время запроса, мы можем вызвать функцию отмены promise, которая будет искать ошибки внутри main. Как возвращаемые значения, блоки try/catch ранее недостаточно использовались, потому как их было трудно правильно использовать с асинхронным кодом.  var request = require('request'); function getQuote() {     return new Promise(function(resolve, reject) {         request('http://ron-swanson-quotes.herokuapp.com/quotes', function(error, response, body) {             if (error) return reject(error);             resolve(body);         });     }); } async function main() {     try {         var quote = await getQuote();         console.log(quote);     } catch(error) {         console.error(error);     } } main(); console.log('Ron once said,'); Выполните этот код, и Вы сможете увидеть найденное исключение через изменение URL-запроса во что-то похожее к http://foo. Преимущества Есть несколько довольно приятных преимуществ, которые могут действительно изменить способ, которым мы писали асинхронный код JavaScript. Возможность написать код, который работает асинхронно, но выглядит синхронным и делает такие программные конструкции, как return и try/catch, проще в использовании, безусловно, поможет сделать язык более доступным. Лучшей частью является то, что мы можем использовать нашу новую особенность со всем, что возвращает promise. Для примера, возьмем библиотеку Twilio Node.js library. Вы также должны иметь учетную запись Twilio. Начните с запуска npm install twilio. Затем добавьте следующее в файл под названием twilio.js и замените поля в линиях, отмеченные // TODO Вашими собственными учетными данными и цифрами. ./node_modules/.bin/babel-node twilio.js var twilio = require('twilio'); var client = twilio('YOUR_TWILIO_ACCOUNT_SID', 'YOUR_TWILIO_AUTH_TOKEN'); // TODO async function sendTextMessage(to) {     try {         await client.sendMessage({             to: to,             from: 'YOUR_TWILIO_PHONE_NUMBER', // TODO             body: 'Hello, Async/Await!'         });         console.log('Request sent');     } catch(error) {         console.error(error);     } } sendTextMessage('YOUR_PHONE_NUMBER'); // TODO console.log('I print out first to show I am async!');   Так же, как мы показали выше с функцией getQuote, мы отметили sendTextMessage как async, что позволяет ему ждать (await) решения, возвращенного promise с client.sendMessage. Подводя итоги Вы увидели, как можно, используя преимущество предложения функции ES7, улучшить наш опыт написания асинхронного JavaScript. Мы очень взволнованы предложением Async/Await, что сейчас развивается, но пока мы этого ждем, можно использовать Babel, чтобы получить преимущества уже сегодня, со всем, что возвращает promise. Предложение недавно вышло и нуждается в обратной связи. Можете использовать его с Вашими удивительными вещами, которые Вы можете построить. Источник: https://www.twilio.com/blog/2015/10/asyncawait-the-hero-javascript-deserved.html
Роль сертифікації для компанії та співробітника

Автор: Олександр Марченко

Введение  Продолжаем с Вами знакомиться с понятием профессиональной сертификации, и в этой части поговорим о роли сертификации для компании и для сотрудника. Большинство наших знакомых ИТ-специалистов предлагают следующие варианты обоснования целесообразности сертификации: Требуется для компании в рамках программы развития сотрудников. (Нечто подобное в Британии сделали обязательным, ознакомьтесь с понятием Chartered IT Professional); Рассчитываю на бонусы или повод для повышение заработной платы; Рассчитываю на способствование карьерному росту; Хочу подтвердить свои знания и навыки. Каждый из нас когда-то приходил к подобным умозаключениям, но кто из нас хоть однажды задумывался о том, чего ожидает компания от сертификации? Попробуем себе представить… Партнерские программы с вендором. Каждый вендор имеет программы Gold/Silver partner и подобные им. Так, когда заказчик видит подобное свидетельство качества, у него повышается уровень доверия и лояльности. Зачастую такие программы партнерства подразумевают не только финансовые взносы и соответствие многим параметрам оценки, но и присутствие в штате компании нужного числа сертифицированных специалистов. «Необходимое и достаточное условие» для участия в конкурсах и тендерах, торгах и т.д. Зачастую для того, чтобы заполучить желаемого заказчика, нужно «помочь» ему составить требования к «ожидаемому» подрядчику. А что может быть еще более непредвзятым, как мнение третьей стороны, как сертификация, выданная независимым провайдером или вендором? К тому же, если у конкурента нет такого преимуществе – победа, считайте, у Вас в кармане. Честолюбие или тщеславие. Если Вы часто бываете в крупных компаниях, особенно ИТ интеграторах, Вы видели у них стену или целый зал славы, стены в котором сплошь увешаны табличками с разными золотыми партнерскими статусами за последние N лет, наградами и почетными грамотами. А в коридорах Вы можете изучать историю сертификации доброй половины ведущих специалистов. Отбор кандидатов. Точно также, как Вы выбираете врача для своего ребенка, сервисный центр для обслуживания автомобиля, юриста с его дипломами и наградами – также и компания в лице рекрутера выбирает себе сотрудника. Вспомните, как часто у Вас просили ссылку на Ваш профиль на GitHub, кто-то спрашивал у Вас, как часто Вы даете советы или ответы на вопросы на StackOverflow или кто-то похвалил Вашу статью на популярной блоговой платформе для ИТ-шников? А как часто Вы заявляли об этом в своем резюме? И как часто Вы включаете номера своих сертификатов и обновляете их на своем профиле в LinkedIn? Думаю, Вам понятно, что сертификация — это какая-никакая гарантия качества знаний сотрудника.  В то же время, могу Вас заверить, что при активной «социальной» деятельности, которая подтверждает Ваши знания и опыт, такой как выступления на тематических конференциях, модерирование хакатонов, ведение интересных блогов, разработка курсов для начинающих разработчиков и т.д., Вам не понадобится сертификация для уверения рекрутера в Вашей надежности и соответствии требованиям проекта. Но, если Вы начинающий специалист, которому нужно оказаться лучше, чем толпы конкурентов, задумайтесь над тем, что заставит рекрутера смотреть именно в Вашу сторону, задумайтесь сможете ли Вы дать компании то, что дорого для нее.
Примусове перевизначення віртуальних методів

Автор: Редакція ITVDN

Введение Некоторые сценарии требуют, чтобы виртуальные методы были переопределены в дочерних классах, к примеру, требование переопределить GetHashCode и Equals. В этом примере будет описано, как применять подобное переопределение. Виртуальные и абстрактные методы При создании виртуального метода в классе создается метод с телом, исполняющим некоторые операции и, возможно, возвращает какое-то значение. Создание метода виртуальным подразумевает его переопределение в дочерних классах. Дочерние классы могут создавать свои методы с другим функционалом. Однако, если при создании дочернего класса не переопределить виртуальный метод, произойдет автоматическое унаследование из материнского класса. Это несколько отличается от абстрактного метода, который может быть добавлен исключительно к абстрактному классу. Абстрактные методы нефункциональны и должны быть переопределены в любом дочернем классе. Могут встретиться ситуации, когда необходимо обеспечить перезапись виртуальных методов дочерним классом, не используя определение этого метода в материнском классе. Это имеет смысл, когда необходимо переопределить виртуальный метод в пользовательском классе или стандартные методы .NET framework. Одним из наиболее простых примеров этой техники является принудительное переопределение методов ToString, Equals и GetHashCode, которые определены в классе System.Object. Это возможно сделать наряду с перегрузкой оператора == для того, чтобы убедиться, что метод Equals не использует банальное сравнение равенства ссылок для Вашего приложения. Для корректной работы необходимо, чтобы методы Equals и GetHashCode были переопределены. Можно также переопределить и ToString для того, чтобы иметь возможность включить важную информацию для использования во время ведения учета записей. Для того, чтобы убедиться в переопределении методов в классах, дочерних от абстрактного класса DataObject, необходимо переопределить их в этих классах. Также необходимо отметить новые методы как абстрактные. Например: public abstract class DataObject {     public abstract override string ToString();     public abstract override bool Equals(objectobj);     public abstract override int GetHashCode(); } Для демонстрации, что может произойти, когда производные типы в данное время не осуществляют абстрактные методы, можно использовать следующий класс. Пустой класс не включает в себя какой-либо из трех методов. public class Employee : DataObject { } При построении проекта будет сгенерировано сообщение об ошибке для каждого «потерянного» метода. В сообщениях будет описание проблемы и выглядеть оно будет следующим образом: 'ConsoleApplication1.Employee' does not implement inherited abstract member 'ConsoleApplication1.DataObject.GetHashCode()' Источник: http://www.blackwasp.co.uk/ForcedOverride.aspx
Співпрограми на основі генераторів Python

Автор: Олексій Орленко

Введение В данной статье, которая является второй из цикла об асинхронном программировании с использованием сопрограмм в Python, мы рассмотрим их классическую реализацию, доступную ещё с Python версии 2.5, при помощи расширенных возможностей генераторов (PEP 342). В Python есть механизм, который создан для удобного описания итераторов: генераторы (generators). Функцией-генератором (generator function) называется функция, которая может отдавать очередное значение при помощи ключевого слова yield и автоматически сохраняет и возобновляет своё состояние при получении следующего значения. При вызове данная функция возвращает итератор, который называется итератором генератора (generator iterator) или объектом генератора (generator object). Под генератором в зависимости от контекста понимают либо функцию-генератор, либо итератор генератора. Пример: Примечание: исходный код всех примеров доступен на GitHub: https://github.com/aqrln/itvdn-blog-async-python-examples def fibonacci():     a, b = 0, 1     while True:         yield b         a, b = b, a + b Данный генератор представляет собой бесконечную последовательность чисел Фибоначчи. Создадим объект генератора: fibonacci_sequence = fibonacci() После этого можно последовательно получать числа Фибоначчи путём вызова   print(next(fibonacci_sequence)) (Встроенная функция next вызывает метод __next__ (next в Python 2) объекта-генератора.) Или, например, получим список пар номеров и значений первых n чисел Фибоначчи: print(list(zip(range(1, n + 1), fibonacci()))) Генераторы являются частным случаем сопрограмм, также называемым semicoroutines (дословно – полусопрограммы). В отличие от классических сопрограмм, которые могут передавать управление в произвольную сопрограмму, генераторы могут передавать его лишь в место вызова метода __next__ (или send, но об этом позже), однако, для реализации асинхронных функций нам это и нужно: сопрограммы будут возвращать управление в цикл событий. В Python 3 существуют так называемые подгенераторы (subgenerators). Если в функции-генераторе встречается пара ключевых слов yield from, после которых следует объект-генератор, то данный генератор делегирует доступ к подгенератору, пока он не завершится (не закончатся его значения), после чего продолжает своё исполнение. Кроме того, yield from на самом деле является не оператором, а выражением, результат которого равен тому значению, которое функция-генератор возвращает при помощи обычного оператора return (оно сохраняется в исключении StopIteration, которое возникает при завершении генератора). Этого уже достаточно для того, чтобы реализовать асинхронное выполнение кода на основе цикла событий, и именно так реализован модуль asyncio в Python 3.4. Однако, для реализации сопрограмм в общем случае у генераторов в Python есть ещё один полезный метод: send(). Он отправляет в генератор значение, которому будет равно yield-выражение генератора (да, yield тоже является выражением, а не оператором). При помощи этих средств уже можно реализовать полноценные сопрограммы. Давайте рассмотрим пример программы, в основе которой лежат две сопрограммы: одна генерирует данные (её в таком случае называют producer), а другая – обрабатывает (consumer). Примечание: здесь и далее примеры кода написаны на Python 3 import time import random def sleep(seconds):     """Сопрограмма, которая приостанавливает сопрограмму,     из которой была вызвана, на заданное количество секунд"""     initial_time = time.time()     while time.time() - initial_time < seconds:         yield def consume():     """Сопрограмма обработки данных"""     running_sum = 0     count = 0     while True:         data = yield         running_sum += data         count += 1         print('Got data: {}\nTotal count: {}\nAverage: {}\n'.format(             data, count, running_sum / count)) def produce(consumer):     """Сопрограмма выдачи данных.     Каждые полсекунды генерирует случайное число.     """     while True:         yield from sleep(0.5)         data = random.randint(0, 100)         consumer.send(data)         yield def main():     # Создание обработчика данных     consumer = consume()     # Запуск сопрограммы     consumer.send(None)     # Создание производителя данных     producer = produce(consumer)     # Цикл событий (event loop)     while True:         next(producer) if __name__ == '__main__':     main() Здесь функция-генератор produce – это producer-сопрограмма, consume – consumer-сопрограмма, sleep вспомогательная сопрограмма, которая используются сопрограммой consume для приостановки выполнение своего «потока» на заданное время. В начале работы программы создаются объекты-генераторы consumer и producer и запускается сопрограмма consumer. Её необходимо запустить заранее (либо послав её значение None, либо вызвав next(consumer), что, на самом деле, одно и то же), так как единственным значением, которое можно отправить в генератор, пока он не запущен, является None. Причина этого в том, что значение, которое передаётся при помощи метода send(), становится значением того yield-выражения, при помощи которого генератор вернул управление, и если он ещё не запущен, то данное значение некуда присваивать. Затем запускается некоторое подобие цикла событий (с единственным возможным событием: генерация новой порции данных). Если бы в Python на уровне языка была поддержка полноценных сопрограмм с возможностью передачи управления в заданную сопрограмму, то можно было бы обойтись без него, но генераторы могут передавать управление лишь в вызывающую функцию, поэтому требуется сущность, которая управляет выполнением сопрограмм. Ей и является этот цикл. Рассмотрим сопрограмму consume. После инициализации в бесконечном цикле она повторяет следующие действия: ожидание данных при помощи yield-выражения (и, поскольку yield отдаёт управление циклу событий, в то время, пока данная сопрограмма находится в состоянии ожидания, может выполняться другой код) и их обработка: увеличение счётчиков и вывод на экран полученного числа, общего количества полученных чисел и их среднего значения. Внутри сопрограммы produce тоже находится бесконечный цикл. На каждой итерации она отдаёт управление сопрограмме sleep, которая просто отдаёт управление циклу событий через сопрограмму produce, пока не пройдёт заданный промежуток времени, а затем генерирует случайное число и отправляет его объекту-генератору consumer при помощи метода send(). Таким образом, мы реализовали параллельное исполнение двух функций внутри одного потока. Однако, в отличие от настоящей многопоточности, функции сами решают, когда им следует переключиться.   Давайте сравним это с абсолютно аналогичной программой, построенной на классических потоках: import time import random from threading import Thread, Condition class Consumer(Thread):     """Класс потока – обработчика данных"""     def __init__(self):         """Конструктор класса"""         super().__init__()         self.condition = Condition()         self.received_data = None     def run(self):         """Код, исполняемый в потоке"""         running_sum = 0         count = 0         while True:             with self.condition:                 # Ожидание доступности данных                 self.condition.wait()                 # Получение данных                 data = self.received_data             # Обработка данных             running_sum += data             count += 1             print('Got data: {}\nTotal count: {}\nAverage: {}\n'.format(                 data, count, running_sum / count))     def send(self, data):         """Метод отправки данных в обработчик"""         self.received_data = data class Producer(Thread):     """Класс потока – производителя данных"""     def __init__(self, consumer):         """Конструктор класса"""         super().__init__()         self.consumer = consumer         self.condition = consumer.condition     def run(self):         """Код, выполняемый в данном потоке"""         while True:             data = random.randint(0, 100)             with self.condition:                 self.consumer.send(data)                 self.condition.notify()             time.sleep(0.5) def main():     # Создание и запуск обработчика данных     consumer = Consumer()     consumer.start()     # Создание и запуск производителя данных     producer = Producer(consumer)     producer.start() if __name__ == '__main__':     main() Как видите, в обоих случаях код очень похожий. Сопрограммы позволяют описывать логику работы максимально приближенно к многопоточному коду, однако, в данном случае решение с сопрограммами короче, элегантнее и не требует синхронизации потоков. 
Notification success