Быстродействующие SSD нового поколения

Не так давно в продажу поступили новые SSD-накопители с интерфейсом SAS-3 (12 Гбит/с) компании HGST, ведущего производителя твердотельных SAS/FC-накопителей корпоративного класса. Компания, которая была основана пионерами отрасли жестких дисков, продолжает свою историю инноваций, и теперь стала первым поставщиком, предложившим рынку твердотельные накопители с этим высокоскоростным интерфейсом. Эти быстродействующие устройства обеспечивают скорость чтения до 1200 Мбайт/с, а записи — до 750 Мбайт/с.
Прежде чем подробно рассмотреть характеристики новых дисков, поговорим о преимуществах интерфейса SAS-3.
Во-первых, его максимальная пропускная способность — 12 Гбит/с — вдвое больше, чем у предшественника. Предельная скорость обмена с SSD-накопителями, подключенными по 6-гигабитному интерфейсу, составляет 550—550 Мбайт в секунду.
Во-вторых, в интерфейсе реализован механизм автоматической подстройки параметров передатчика на основе информации, получаемой от приемника. Высокое качество сигнала, обеспечиваемое благодаря этому и другим механизмам, позволяет использовать кабели длиной до 10 (пассивный медный кабель), 25 (активный медный кабель) и 100 (оптический кабель) метров.
Кроме того, SAS-3 является эффективным решением для использования в SAN. Превосходя в быстродействии 8-гигабитный FC и лишь немного уступая 16-гигабитному, 12-гигабитный SAS в то же время значительно дешевле последнего. При этом он обеспечивает тот же уровень надежности.
Наконец, обратная совместимость накопителей SAS-3 с интерфейсом SAS-2 позволяет использовать их в существующей инфраструктуре хранения, с тем чтобы полностью высвободить их потенциал после модернизации.

Ultrastar SSD800MH
Старшая модель нового семейства — Ultrastar SSD800MH при подключении по интерфейсу SAS 12 Гбит обеспечивает следующие характеристики: скорость чтения до 1200 Мбайт/с, записи до 750 Мбайт/с. Скорость ввода-вывода такова: до 145 000 последовательных операций чтения и до 100 000 последовательных операций записи в секунду (произвольные блоки). Это более чем в 100 раз быстрее жестких дисков и вдвое больше, чем дают твердотельные накопители с 6-гигабитным интерфейсом. Что касается срока службы устройства (тип памяти — MLC NAND), то модификация емкостью 800 Гбайт позволяет в общей сложности записать 36,5 Пбайт данных, или 20 Тбайт в день. Это означает, что диск можно перезаписывать 25 раз в день на протяжении 5 лет. Гарантийный срок на эти устройства составляет 5 лет либо определяется максимальным объемом записанных данных. Предлагаются также устройства аналогичного класса емкостью 400 и 200 Гбайт.
Области применения Ultrastar SSD800MH — высокочастотный трейдинг, онлайновая обработка транзакций, анализ данных и другие задачи, требующие интенсивного обмена с внешней памятью и в то же время высокого быстродействия.

Ultrastar SSD800MM
Эта модель, которая также выпускается в модификациях на 800, 400 и 200 Гбайт, немногим уступает предыдущей, в основном в отношении количества циклов записи. Устройство можно полностью перезаписывать 10 раз в день. Максимальная скорость чтения — 1150 Мбайт/с, записи — 700 Мбайт/с. Максимальная частота ввода-вывода: 145 000 последовательных операций чтения и до 70 000 последовательных операций записи в секунду (произвольные блоки). Тип используемой памяти: MLC. Максимальный объем записи: 14,6 Пбайт, или 8 Тбайт в день в течение 5 лет.
Рекомендуемые области применения — нулевой ярус многоярусных (многоуровневых) систем хранения данных, высокопроизводительные вычислительные системы, системы обработки и др.

Ultrastar SSD1000MR
Эти накопители, выпускаемые в модификациях на 250, 500 и 1000 Гбайт, рассчитаны преимущественно на работу в приложениях, ориентированных на считывание данных. Максимальная скорость чтения — 1200 Мбайт/с, записи — 700 Мбайт/с. Предельная частота считывания: 145 000 операций в секунду, записи — 20 000 операций в секунду. 1000-гигабайтная модель позволяет записать в общей сложности 3,7 Пбайт данных, что эквивалентно 2 Тбайт в день на протяжении 5 лет. Иными словами, при пятилетней эксплуатации диск можно переписывать полностью два раза в день.
Рекомендуемые области применения — нулевой ярус считывания данных высокопроизводительных систем хранения, быстродействующие вычислительные системы, системы обработки видео, «облачные» сервисы информационно-вычислительного обслуживания, компактные системы и системы с низким энергопотреблением.

Все накопители выпускаются в 2,5-дюймовом форм-факторе, в модификациях с потребляемой мощностью (во время ввода-вывода) 9 или 11 Вт. Максимальное время наработки на отказ — 2 млн. часов.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Социальная сеть myApollo: все яйца в одну корзину

Если бы мы c вами жили в Торонто, то наверняка заметили на улицах города множество боксов и стендов с рекламой некоего нового сервиса myApollo. И в один прекрасный день не выдержали бы и отправились в Гугл выяснять, что же этот сервис собой представляет и почему у него такая активная рекламная компания. Живем мы, конечно, не в крупном канадском городе, но повод разузнать как можно больше о myApollo у нас был. Какой – расскажем чуть позже, пускай это будет тизер.

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

MyApollo — детище стартапа Arroware родом из Торонто. Его основали двое молодцов-удальцов Харви Медкаф (Harvey Medcalf) и Фил Кинсман (Phil Kinsman), которые каким-то образом сумели убедить инвесторов в том, что их проект гораздо круче чем Facebook, Dropbox, Google Drive, iTunes и Etsy вместе взятые. Сыграли роль, пожалуй, и патриотические амбиции разработчиков: навскидку из канадских IT-компаний вспоминается только Blackberry, да и у тех дела сейчас идут не лучшим образом, так что парни из Торонто явно не прочь поднять имидж своей страны.

Харви Медкаф, CEO и президент Arroware

Как водится, в один прекрасный день будущим создателям myApollo пришла в голову простая мысль: почему мы общаемся с друзьями, выкладываем свои фотографии и видеоролики на одном сервисе, а храним все свои файлы на другом? Почему бы не объединить площадку для общения с облачным хранилищем, чтобы пользоваться только одним сервисом? Ведь если подумать, то при нынешнем развитии технологий (да и той роли, которые играют цифровые данные в нашей жизни) просто неприлично иметь столько аккаунтов на стольких площадках. В общем, поразмыслили канадские парни и придумали мощный дата-центр, в котором можно еще и общаться.
В myApollo есть все, что нужно иметь современной социальной сети: «стена», личный профиль, возможность переписываться с другими людьми, цитировать, оценивать, обмениваться фотографиями, — но все это подается под соусом облачного хранилища. То есть в отличие от того же Facebook делиться можно файлами даже больших размеров: часовым презентационным или портфолио, собранным за десять лет работы.

Как утверждают сами ребята из Arroware, они просто взяли и убрали все искусственные ограничения, которые ставят на пути интернет-пользователей разработчики существующих платформ и даже производители «железа». Как и положено облачному сервису, myApollo предлагает единое файловое хранилище с простым доступом с любого компьютера и мобильного устройства. Грубо говоря, находясь в любой точке планеты, юзер может написать пост на свою страничку и тут же проиллюстрировать его парой (десятков) музыкальных треков из тех, что хранятся в его облачном хранилище. Ну, или прислать одному из контактов в myApollo весь свой фотоальбом на несколько десятков гигабайт — пусть сразу видит, с кем имеет дело. Если верить официальному сайту сервиса, в разработке находятся приложения для iOS, Android, Windows и OSX.

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

Кстати, создатели проекта обещают, что информацию о пользователях сдавать «налево» не собираются, — все максимально прозрачно и безопасно. Прибыль планируют получать только от размещения баннеров и таргетированной рекламы. А вот определенной целевой аудитории у сервиса нет, по крайней мере, так утверждают сами разработчики, — как говорится, молодым везде у нас дорога, пожилым всегда у нас почет.
Казалось бы, идея myApollo лежала на поверхности: ребята просто взяли и соединили в один сервис то, что нужно современному пользователю интернета, не придумав ничего нового. Но мы же знаем, что новое — это не только хорошо забытое старое, но и с умом доработанное актуальное. Просто дай людям то, что они хотят – все просто. Так, кажется, еще Джобс говорил, а уж он-то знал толк в позиционировании. Правда, возникает резонный вопрос: как втиснуться на и без того заполненный рынок социальных сервисов, облачных хранилищ и файлопомоек, ведь среднестатистическому пользователю будет нелегко объяснить, чем myApollo лучше других соцсетей. Одним словом, нужна мощная -кампания, чем стартаперы на данный момент как раз и занимаются. А дальше уже дело за «малым» – запустить, наконец, сервис, привлечь пользователей и не отпугнуть их мелкими недоработками, которые неизбежны на начальных этапах существования любого проекта. Но в ребят из Arroware мы верим.

Ах, да, вы, наверное, давно хотите спросить, почему мы пишем о какой-то социальной сети в корпоративном блоге Dell? Все просто: myApollo использует наши сервера для обработки и хранения того огромного объема данных, которыми счастливые пользователи буду друг с другом делиться на новой площадке. Dell спроектировал для myApollo гибкую инфраструктуру, мощности которой можно постепенно наращивать по мере развития платформы. Она включает в себя новейшие сервера, накопители и сетевые устройства, которые обеспечивают надежную защиту данных и отличаются огромной отказоустойчивостью. Сервис будет работать на blade-серверах Dell M620, установленных в стойках M1000E. Сетевая инфраструктура будет использовать коммутаторы линейки Dell Force10, в частности, Force10 MXL, Force10 S4810, Force10 S50N и Force10 S60N. И не стоит также забывать про самые надежные хранилища Dell.

В общем, ждем даты «Х» (запуск приложения для Android уже запланирован на 6 сентября) и смотрим, что же получилось у Arroware. Быть может, мы окажемся причастными к созданию нового Facebook или, того лучше, нового Google.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Во Франции создается «летающий автомобиль»

imageВо Франции создается «летающий автомобиль» — малогабаритный самолет вертикального взлета и посадки, который можно будет отправлять в полет хоть из двора жилого дома. Работы по данной программе были начаты в 2007 году в индивидуальном порядке инженером Мишелем Агиларом, проживающим недалеко от Тулузы, в городке Кастане /департамент Верхняя Гаронна/.

Летательный аппарат, которому его создатель дал название Xplorair (покоритель воздуха) снабжен двумя реактивными двигателями, вмонтированными внутрь крыла. Их реактивные струи отклоняются щитками дефлекторов, придавая необходимое направление вектору тяги. В основе принципа работы двигателя — эффект Коанда, то есть, стремления струи жидкости, вытекающей из сопла, при определенных условиях изменять направление, как бы «прилипая» к ближайшей выпуклой поверхности.
На этой основе Агилар разработал свой «ТермоДвигатель», сочетающий характеристики турбореактивного и прямоточного воздушного двигателей. Эта новинка позволяет летательному аппарату совершать взлет не строго вертикально, а по резко восходящей линии, как это делают птицы.

В отличие от многих изобретателей, Мишелю Агилару повезло — его «летающим автомобилем» немедленно заинтересовалось Главное управление вооружений министерства обороны Франции, а также министерство промышленности. Ведомства выделили в 2011 году на поддержку проекта сумму в 1,5 млн евро. В 2013 году к работам присоединилась и специализированная фирма Altran, которая поручила группе своих сотрудников заняться разработкой авионики и структуры планера.
В настоящее время работы координируются консорциумом из нескольких фирм-партнеров. Возглавляет его тулузская компания Comat aerospace, которая непосредственно ведет работы над двигателем. Патентное ведомство уже выдало необходимую документацию на новинку.

По словам самого Агилара, приведенным газетой «Паризьен», на настоящий момент удалось добиться уровня в 70-75% от проектируемой мощности двигателей, что является весьма неплохим результатом.
В случае успеха летательный аппарат нового типа будет способен совершать полеты на высотах до 2,5 тыс метров на скорости в 200 км в час. При этом его будут заправлять биотопливом, созданным на основе переработки водорослей, что позволит снизить долю расходуемого классического авиационного топлива на 15-20%.
Агилар надеется, что ему удастся представить первый прототип «Покорителя воздуха» на Авиационно-космическом салоне в Ле-Бурже в 2017 году.

via ИТАР-ТАСС ПАРИЖ, 2 сентября. /Корр.ИТАР-ТАСС Михaил Тимофеев/

PS: желтая статья, но все таки интересно.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Руководство SimpleMembership в ASP.NET MVC 4

С появлением ASP.NET MVC 4 и WebMatrix команда mvc стремиться сделать вещи проще для разработчика. Исходя из отзывов одно из направлений для улучшения была выбрана безопасность asp.net. 

ASP.NET MVC 4 шаблон проекта Internet добавил несколько новых очень полезных функций, которые построены с использованием SimpleMembership. SimpleMembership принес простую настройку ролей и пользователей, а также добавил поддержку OAuth. Однако новый провайдер не совместим с существующим ASP.NET Membership Provider.

В этом посте я расскажу о том, что такое SimpleMembership и как его использовать в проекте ASP.NET MVC 4.


Что такое SimpleMembership
  • SimpleMembership разработан для замены предыдущей версии ASP.NET Membership Provider (ASP.NET Role)
  • SimpleMembership решает те же самые задачи, но делает их проще для разработчика и приспосабливается к современным требованиям обеспечения безопасности
  • Контроллер
    AccountController в шаблоне проекта Interner ASP.NET MVC 4 требует SimpleMembership и не совместим с использованем старых версий
  • Досадная новость в том, что Web Site Administration Tool (WSAT) не совместим с SimpleMembership.
Система ASP.NET Membership System была представлена в 2005 году. Она была разработана для решения общих задач, таких как регистрации на сайте с использованием связки логина и пароля, хранения профиля в базе данных SQL Server. Также были добавлены механизмы расширения, позволяющие переопределить стандартную логику работы MembershipProvider и RoleProvider. 8 лет назад этот механизм справлялся со своей задачей, но сегодня это неудобный инструмент. Если профилю пользователя требуются дополнительные поля, то все они хранятся в одной колонке и для доступа требуют вызовов API соответствующего провайдера.

В ASP.NET WebPages и WebMatrix по новому представлены многие вещи, например движок представлений Razor и SimpleMembership.

Почему использование ASP.NET Membership не рекомендуется
Стандартный провайдер прекрасно работает, если выполняются следующие условия: вся информация будет храниться в полной версии базы данных SQL Server и то, что все необходимые данны представлены в виде набора атрибутов (UserName, Password, IsApproved, CreationDate...) и другая информация будет предоставлена используя Profile Provider. 

Требуется полный SQL Server по умолчанию
Большинство полнофункциональных провайдеров ASP.NET требуют полную версию SQL Server (т.к. опираются на работу хранимых процедур, на кеш SQL Server и другие возможности сервера). Кроме того, провайдеры по умолчанию не будут работать на SQL Azure.

Трудности работы с другой базой данных
Для работы с базой данных отличной от SQL Server необходимо переопределить набор методов провайдера, которые сильно ориентированы на хранение данных в реляционной базе данных. Во-первых это большой объем работы по переопределению этих методов, а во-вторых скорее всего останется множество неопределенных методов, содержащих System.NotImplementedException, что не красит код.

Ориентация на модель Пользователь > Роль
Существующие поставщики данных строго ориентированы на эту модель, в которой пользователь имеет логин и пароль. Конечно, дополнительные сведения могут быть добавлены через API, но такая модель не подходит для OAuth (там пользователь не имеет пароля). 

Система ориентирована на роли не всегда будет уместна, бывает удобнее использовать модель прав доступа к отдельным объектам или действиям (Claims)

Также требуется жестка схема базы данных с большим количеством blob колонок.

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

Matthew Osborn в своей записи Using SimpleMembership With ASP.NET WebPages объясняет, что SimpleMembership разработан, чтобы легко интегрироваться с вашей базой данных.

SimpleMembership требует, чтобы было 2 колонки в таблице пользователей: «ID» и «UserName». Важная часть здесь, что эти колонки могут иметь любые названия.

Схема таблицы пользователи

Теперь необходимо рассказать об этом SimpleMembership: добавить строку подключения к базе данных.
<code class="xml"><connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=ARCTURUS\SQLEXPRESS;Initial Catalog=MembershipDemoDB;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient" />
  </connectionStrings>
</code>
И определить инициализацию:
<code class="cs">WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "Id", "Name", autoCreateTables: true);
</code>

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

SimpleMembership создал таблицы

SimpleMembership работает со всей линейкой SQL Server (SQL Azure, SQL Server CE, SQL Server Express и LocalDB). Все реализовано как вызовы SQL, что здесь гораздо лучше, чем использование хранимых процедур.

Использование EntityFramework с Code First
Проблема с ASP.NET Membership в том, что она хранит дополнительную информацию об аккаунте сама. Это значит, что нельзя напрямую получить доступ к данным профиля. В том время как SimpleMembership все равно, в какой таблице и как хранятся данные пользователя. Можно легко изменить таблицу с пользователями, например добавить адрес.

<code class="cs">[Table("Users")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }

    public string Address { get; set; }
}
</code>

Теперь можно легко получить доступ к этому полю не используя сам провайдер, а напрямую из базы данных. Это позволяет принимать SimpleMembership как прослойку между базой данных и системой ASP.NET Membership.

Как он реализован я опущу, можно посмотреть в оригинальной записи SimpleMembership. Важно знать, что SimpleMembership унаследован от ExtendedMembershipProvider.

ASP.NET MVC 4 Internet template
В шаблоне по умолчанию реализован следующий механизм работы с SimpleMembership:

ASP.NET MVC 4 Internet template

  • AccountModel.cs описывает базовый аккаунт пользователя и включает атрибуты для базы данных
  • InitializeSimpleMembershipAttribute.cs как раз содержит информацию для инициализации провайдера: какую базу данных использовать, какие поля и другие настройки.
  • AccountController.cs содержит вызовы WebSecurity класс библиотеки WebMatrix.
WebSecurity работает с любым ExtendedMembershipProvider. По умолчанию используется SimpleMembershipProvider, однако можно реализовать свой.

Настройка SimpleMembership
Добавление SimpleMembership в существующий проект
Хотя этот провайдер работает по умолчанию в проекте с шаблоном ASP.NET MVC 4 Internet, некоторые (и я в том числе) создают проект с пустого шаблона. Необходимо добавить 2 : WebMatrix.Data и WebMatrix.WebData. Или установить эти библиотеки через NuGet с одноименными идентификаторами).

WebMatrix data

Теперь необходимо добавить провайдера и указать на использование WebMatrix

<code class="xml"> <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
      <providers>
        <clear />
        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider,WebMatrix.WebData" />
      </providers>
    </roleManager>
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear />
        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>
</code>

Так как WSAT использовать не получится, есть 2 способа создания пользователей и ролей. Если используется модель EntityFramework Code First, удобно будет добавить Micragion с созданием пользователей по умолчанию:

<code class="cs">public partial class AddDefaultUser : DbMigration
{
    public override void Up()
    {
        if (!WebSecurity.Initialized)
        {
            WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "Id", "UserName",
                autoCreateTables:
                    true);
        }

        var roles = (SimpleRoleProvider)Roles.Provider;
        var membership = (SimpleMembershipProvider)Membership.Provider;

        if (!roles.RoleExists("Admin"))
        {
            roles.CreateRole("Admin");
        }
        if (membership.GetUser("Admin", false) == null)
        {
            membership.CreateUserAndAccount("Admin", "SuperAdminPassword");
        }
        if (!roles.GetRolesForUser("Admin").Contains("Admin"))
        {
            roles.AddUsersToRoles(new[] { "Admin" }, new[] { "Admin" });
        }

    }

    public override void Down()
    {
        throw new NotImplementedException();
    }
}
</code>

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

Ссылки


Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Как я учился пользоваться системами постановки задач

image

Я полагал, как и многие из вас, что программа или система для постановки личных задач должна быть одна и в ней все на свете. Довольно долго я гонялся за идеальной системой. Читал пару книг про тайм-менеджмент, читал GTD. Начинал вести свои задачники с блокнотов, тетрадок, потом перешел в электронные пространства, и там стал записывать все то же самое, но уже в Notepad и Word. Время шло, и ко мне стали попадаться веб-версии календарей и постановок задач.

Параллельно с этим стало понятно, что если ставишь задачи, то лучше иметь эту штуку (в которую ставишь задачи) при себе — ведь можно на ходу вспомнить, что делать, а пока дойдешь до компа — уже все забыть. Какое-то время я использовал систему: если подумал, то ставишь будильник на телефоне, чтобы прозвенел через час. Приходишь домой, все забыл и тут будильник — и ты такой пытаешься вспомнить, что он должен означать.

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

Мне кажется маловероятным — сделать идеальную программу на этот счет, но все пытаются. Чем больше она учитывает, тем менее она удобна и, соответственно, тем меньше ей пользуются — а значит она не работает. Вот в такой дилемме живут те, кто пытается организовать наше время через ПО. Возможно, именно поэтому раз в полгода в блогах про стартапы и мобильные приложения мы читаем про новое мега-приложение или про «очень простое и удобное». Короче, таких тем много, выбрать из них что-то трудно, каждый сходит с ума как может. Но это было только вступление.

Про что я, собственно?

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

— Сделать именно в такой-то день и час
— Вспомнить об этой задаче в такой-то день и дальше запланировать конкретно
— В принципе сделать задачу, не в какой-то конкретный срок, а как текучка

Те, кто прочитал GTD Дэвида Аллена, тот знает, что и обрабатывать входящие задачи/заметки/справки можно по системе, как с письмами, об этом чуть ниже. Потом эти читатели узнают, что есть компьютерная программа, сделанная по методике GTD — и срочно пользоваться именно ей. Вот в этом месте хотел бы поделиться своим опытом: почитав GTD, я сделал вывод, что и не надо иметь одну программу на все, главное, чтобы выполнялась система. В итоге я пользуюсь 2-3 программами.

Дальше пойдет конкретика, но если я пишу про GTD, а вы не в теме, что это такое или считаете, что это не для вас и, соответственно, все что я пишу — тоже, то это не так. Дайте шанс :)

Я поделил все свои задачи на несколько видов. Делил я их не теоретически или «по книжке», поделил по факту — какая практика сложилась, такое деление и произошло, а именно:

— Задачи на сегодняшний день, или ближайшие дни, которые надо сделать. Причем задачи обязательные, от которых нет возможности отвертеться (ставлю в «Due», см. ниже)
— Задачи в конкретный день и время (ставлю в «Due» или iCal)
— Задачи, про которые «надо вспомнить ближе к такому-то числу» (iCal или Omnifocus)
— Текучка (Omnifocus)
— Заметки (Omnifocus или родное приложение «Заметки»)
— Справочная инфа (Omnifocus)
— Отдельно пароли (Omnifocus или 1Password)

При этом есть правило: если не знаешь куда ставить — кидай во «Входящие» Omnifocus.

И сразу еще пару правил, для тех, кто плохо помнит/не читал GTD:

1. Не знаешь как начать задачу или долго не можешь приступить — поставь простую задачу типа «Прочитать первую страницу выдачи гугла на заданную тему». В общем, начни хоть с чего-нибудь. Дальше втянешься.
2. Задачники нужны, чтобы не забивать себе голову. Поставил в одном задачнике — стирай в другом. Записал хоть куда-нибудь — перестань переживать за эту задачу.

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

Due.

image

Об этом стоит больше всего рассказать. Due дает возможность поставить на конкретное число и время. В Due задачу можно откладывать одним нажатием на 10 минут, или на 1 час, или на 1 день. В Due можно ставить задачу на одно из времен дня (утро, день, после работы, вечер). Можете эти времена задавать сами. В Due можно задачу циклить, чтобы она повторялась каждый 1 день, или каждые 2 дня или какой угодно период, выбирайте сами.

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

Due — приложение для iPhone, платное, блин. Для Android, к сожалению, не нашел. Делайте свое такое же как Due для Android :)

Omnifocus.

image

Программа для мака, айфона, айпада, сделана по системе GTD.
Есть еще Things, как мощный конкурент, но я в свое время выбрал Omnifocus, как минимум из-за этого, что у него синхронизация через Интернет была. Для Windows тоже есть полно своих GTD-app: habrahabr.ru/post/114841/

Еще у Omnifocus по сравнению с Things было преимущество в «монструозности». Я имею ввиду, что она была посложнее, чем Things, как бы более серьезная. Пропользовав почти 2 года могу сказать, что теперь подумываю о более простых, но более действенных вариантах. Omnifocus дает систему, но не «заставляет» тебя что-нибудь с этим делать. А надо чтобы «заставлял». Однако, довольно плотная интеграция в систему, несколько очень полезных hot key — очень удобно. Интеграцию с почтой так и не осилил.

iCal или 1Password.


Тут все понятно: 1Password — программа для хранения паролей с удобным hot key на маке, а iCal — календарь, синхронизированный с вебом, гугл-календарем и мобильными устройствами.

Что интересного из этой серии видел еще.

Про главное рассказал, теперь размышления на тему. Меня всегда интересовала проблематика — надо автоматизировать и систематизировать деятельность с корзиной, куда складываются входящие задачи. Очень интересное, что я видел из этого: Mailbox для iOS. Удобная работа с входящими письмами с целью всегда оставлять пустой почтовый ящик. Там письмо можно отложить, удалить, архивировать, положить в конкретный список. Очень не хватает десктоп-клиента.

Сейчас частенько этой корзиной становятся соц. сети и личные сообщения в ней. Т.е. тут я могу попасть впросак с пользователями Хабра, они обычно люди системные настолько, что «для писем у них почта», но я знаю просто целые пласты людей, которые личную и деловую переписку ведут в соц. сетях. Вконтакте даже сделало небольшой шаг навстречу — сделали возможность отмечать важные сообщения. Какая-никакая, а уже фильтрация.

На Facebook есть почтовый адрес, письма на который приходят в личные сообщения. Верно и обратное. У Вконтакте только в одну сторону работает. В общем, уверен, что с входящей информацией через соц. сети можно как-то более системно работать. Если бы, скажем Gmail сделало какой-нибудь спец. ящик для пользователей Facebook с теми возможностями, что есть у Гугла — уже был бы прогресс.

Очевидными «корзинками» для входящих задач являются телефонные звонки и смски. В случае с андроидом это можно решить на системном уровне, как я понимаю, в случае с iOS — надо ждать самого Apple. Представьте, вам позвонили, поговорили, после разговора предлагается закинуть одной кнопкой во Входящие с именем, временем и продолжительностью звонка. По этим данным уже можно разобраться, что надо записать. С смской еще проще, там текст смс становится примечанием заметки.

Если есть мнения по этим и другим вопросам организации дел и времени, будет интересно услышать мнения )

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Amazon открыл доставку электроники в Россию



In Soviet Russia:

Сегодня интернет-магазин Amazon начал доставку потребительской электроники в Россию. Соответствующие изменения были внесены в систему заказа товаров на сайте компании 2 сентября. Полный список стран, куда осуществляется доставка можно посмотреть тут.


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

Amazon является крупнейшим интернет-магазином в мире. Компания осуществляет доставку в 65 государств мира. В 2012 году компания отчиталась о выручке в 61 миллиард долларов.

Напомню, что не так давно в Россию официально пришел PayPal, а еще раньше eBay, что во многом расширило потребительские возможности россиян.

В 2012 году в России, по данным Ассоциации компаний интернет-торговли, объем рынка электронной коммерции достиг 405 миллиардов рублей. Лидером на российском рынке онлайн-торговли является компания Ozon.ru. В 2012 году ее оборот достиг 15,2 миллиарда рублей. По данным экспертов, до 44 процентов интернет-продаж приходится на потребительскую электронику. Из этого можно сделать вывод, что крупные ритейлеры стараются отхватить свой кусок от динамично развивающегося российского рынка онлайн-торговли, но что же из этого выйдет?..

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


МАКС 2013 (фото на 50 мб)

В четверг довелось побывать на МАКСе 2013. Тогда была еще бизнес-часть выставки, поэтому мне удалось посмотреть экспозицию без рекордных толп, которые салон собрал в выходные.



Фотографий там сделал немало, и решил оформить их в новую форму фоторепортажа — в GIF. Обычно внутри павильонов, без равномерного фона, сложно снимать какие-либо технологические штуки или их макеты — теряются детали из-за избытка деталей позади основного объекта съемки. Думаю анимация позволит лучше сформировать представление о предметах.
Трафик — 55 мб.

Дайте время на загрузку всех изображений, и приступим.

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

На фото «Ресурса-П» я набросал примерную схему своего маршрута:



С погодой не повезло — было пасмурно, съемка под открытым небом не предвещала красочности, поэтому, в надежде, что распогодится, первым делом отправился в павильоны. (Как стало ясно через пару дней, мое «не повезло с погодой» не шло ни в какое сравнение с тем как людям не повезло с ней в субботу).

На подходе к павильонам, приветственно махали ладошками пролетающим самолетам, радары ПВО:

ПВО


Там были С-300, С-400, «Тунгуска», кажется «Буки», но я не фанат средств уничтожения себе подобных, поэтому не уделял им большого внимания.

Только вот такая хитрая штука, показалась забавной:

Агат

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

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

Современный перспективный вертолет Ка-62.



Взгляд в кабину порадовал современным салоном с отсутствием десятков циферблатов всяких -ометров.



Ракетные детали нашлись еще до космического павильона.
Легендарный двигатель НК-33, который так и не добрался до Луны в составе ракеты Н1, но спустя сорок лет обрел вторую жизнь на американской частной ракете Antares.



А эти экспонаты — другой повод вспомнить частную космическую программу США.



Это продувочные макеты двух схем, которые могут стать достойным конкурентом для Grashopper компании SpaceX. Это два типа возвращаемых первых ступеней российской ракеты-носителя «Ангара». Во время запуска ракеты они должны работать как разгонные блоки, потом отсоединяться на высоте примерно 70 км, и совершать самолетную посадку на обычные аэродромы. Учитывая нынешнее развитие беспилотников, схема должна стать очень простым и элегантным способом снижения стоимости орбитальных запусков.

Вот так должна выглядеть полная ракетная сборка:

БайкалБайкал


Судя по названию его посадка предполагалась где-то в районе озера Байкал, при условии пусков с Байконура.

Обычная «Ангара»


Проблема только в том, что «Кузнечик» Элона Маска уже во всю по Техасу прыгает, а у нас только макеты с выставки на выставку который год возят.

«Энергия» привезла макет ППТС — перспективного корабля, который должен стать заменой «Союзу» и обеспечить возможность доставки экипажей до Луны and beyond.



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

Рядом макеты ракетных двигателей

РД-180

НПО Лавочкина продемонстрировало несколько макетов своих аппаратов, которые уже летают или готовятся к полету.

НПОЛНаш старый знакомый «Электро-Л»



«Радиоастрон»



А вот единственная ближайшая межпланетная надежда России — Луна-25. Раньше ей дали неудачное название «Луна-Глоб», но потом-таки отважились продолжить советскую нумерацию, признав преемственность с той эпохой.



На дальнем плане изображен — «Лунный полигон» — концепция автоматической исследовательской базы, которую вынашивают в НПОЛ.

Недавно стало известно, что запуск Луны-25 снова откладывается. Сначала про 2015 говорили, теперь уже «Не раньше 2016-го».

О ГЛОНАСС напоминало крайне мало экспонатов. Видимо до сих пор там все находятся под впечатлением недавнего запуска. Нашлась только вот такая аппаратура:



Исследовательский центр Келдыша представил макет своей передовой разработки — ядерного ракетолета.


Читабельная версия плаката

Ракетолет

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


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

Начал с исторической части. Этот МиГ-3, насколько я знаю — полная рабочая реплика. Наверно, только боевого оружия не хватает. Но летает он точно.


На рабочий стол

Далее — отечественная гордость.

Су-35С


Гигант МиГ-31


Ми-28Н тоже хорош.


На рабочий стол

Самолет дальнего радиолокационного обнаружения А-50


На рабочий стол

Стратегический бомбардировщик Ту-95


На рабочий стол

ВМ-Т «Атлант», который возил элементы ракеты «Энергия» и «Буран».

Атлант



Вертолеты были представлены и в отдельной экспозиции

Ка-52

Аллигатор

Затем в небе раздался рев двигателей, и в воздухе появился европейский истребитель «Рафаль».



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



Эти автожиры напомнили легкие мотороллеры. UPD: К сожалению, цены пока значительно выше чем у мотоциклов.
Кстати, производитель российский.

А это обычный планер. Внимание привлек тот факт, что он привязан (!) к земле. Похоже его реально поднять в воздух сильным порывом ветра.



Производители беспилотников, кажется черпают вдохновение в книге «Секретные проекты Гитлера»:









Пока я шел к полю, в небе крутился Ми-24ВМ (экспортный вариант называется Ми-35М)

Ми-24

Когда моя цель была достигнута, на взлетную полосу выкатился гигант Airbus A380-800. Самолет поразил своими размерами и характеристиками по вместимости — до 853 человек, при этом у него очень короткое расстояние пробега на взлете и посадке. Конечно, на выставке он летал пустой, но и так должен быть весьма удачной машиной.


На рабочий стол

А380

Отлетали еще два российских самолета.

Один из них Ту-214:


На рабочий стол

Ту-214

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

МиГ-29
МиГ-29

Су-27


Су-27




На рабочий стол

Су-30СМ



МиГ-35

На рабочий стол

МиГ-35


На рабочий стол

МиГи, конечно, полностью оправдывают свое название — носятся как угорелые, отказываясь попадать в фокус. У «сушек» есть несколько приемов, которые позволяют им практически зависать в воздухе, поэтому сфокусироваться легче.

В небо полетела легкая авиация: модернизированная иномарка «Ан-2-100» и прочие «Рысачки».



К сожалению, время поджимало и пришлось отправляться на автобус. Уже почти у проходных меня снова настиг рев двигателей и над МАКСом промчался Т-50.



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

Т-50

Красавец. Других слов нет.

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

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

БлагодарностьЗа организацию поездки выражаю благодарность компании "Даурия Аэроспейс" и лично Ляне Машуковой.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Федеральный закон № 243, или Тихая пенсионная реформа

счастливая старость

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

Однако факт остается фактом: «… с 1 января 2014 г. будет осуществлен т. н. страховой маневр — сокращены с 6 до 2% отчисления на формирование накопительной части пенсии. Высвободившиеся 4% пойдут на финансирование страховой части.»

Ну, кто там спрашивал, от чего отвлекают наше внимание?! Здесь был горький смайлик с кривой ухмылкой.

Кому интересно / небезразлично, добро пожаловать под кат!

Итак, пруфлинки. Да, есть такой закон, просто тихий-тихий. Прямо мышка под веником.
Чтобы понимать, о чем речь, уточним терминологию. Из чего же состоят пенсионные накопления и как используются?

Зайдем на официальный сайт Пенсионного Фонда РФ (цитирую со страницы Будущим пенсионерам):
  1. Страховая часть. «Средства страховой части Вашей будущей пенсии фиксируются на Вашем индивидуальном лицевом счете и ежегодно индексируются государством… Физически эти деньги направляются на выплату пенсий нынешним пенсионерам
  2. Накопительная часть. «Средства накопительной части Вашей будущей пенсии учитываются ПФР в специальной части Вашего индивидуального лицевого счета. По Вашему решению они передаются одной из управляющих компаний или негосударственному пенсионному фонду для инвестирования.»
Со страховой частью вроде бы все понятно. Союзных денег давно не осталось, нынешних пенсионеров поддерживаем мы с вами.

Накопительная часть вызывает куда больше вопросов. Как она будет использована при выплате пенсий нам с вами, что с ней можно сделать, достигнув пенсионного возраста? Копаем дальше: О пенсионных накоплениях. Там же можно скачать текст закона № 360-ФЗ О порядке финансирования выплат за счет средств пенсионных накоплений.

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

За счет средств пенсионных накоплений, сформированных в пользу застрахованного лица, осуществляются следующие виды выплат:
1) единовременная выплата средств пенсионных накоплений (далее — единовременная выплата);
2) срочная пенсионная выплата;
3) накопительная часть трудовой пенсии по старости;
4) выплата средств пенсионных накоплений правопреемникам умершего застрахованного лица.

Статья 3. Реализация права застрахованного лица на выплаты за счет средств пенсионных накоплений
<...>
3. Размер выплат, указанных в пунктах 1 — 3 статьи 2 настоящего Федерального закона, определяется исходя из суммы средств пенсионных накоплений, учтенных в специальной части индивидуального лицевого счета либо на пенсионном счете накопительной части трудовой пенсии застрахованного лица на день, с которого назначается соответствующий вид выплат.
Итого:
  • предусмотрено несколько схем пенсионных выплат
  • все они зависят от накопительной части

  • возможно наследование пенсионных накоплений

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

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

Что же несет нам федеральный закон № 243 в таком разрезе? Да ничего особенного, у нас просто собрались втихаря отобрать две трети этого вклада. В старости мы будем более зависимы от милости государства страховой части пенсии и родственникам оставить сможем меньше. Пусть сейчас многие и не верят в пенсионную систему, но речь идет про конкретные деньги и отбирают эти деньги у нас уже сейчас.

Тех, кто никогда не слышал про эти реформы, чьи деньги сейчас уйдут в пользу ПФР, очень много. Вот здесь насчитали 162 миллиарда рублей в год. Мне кажется, сумма великовата для покрытия дефицита в пенсионном бюджете. Но этот вопрос будет интересен скорее РосПилу и иже с ним.

Цель данного поста — коллективный поиск наиболее выгодного решения для каждого из нас. Обзор Гаранта предлагает два варианта: переводить средства в негосударственные пенсионные фонды или выбирать управляющую компанию. Казалось бы, нам дают всего две альтернативы, или сваливать из ПФР или соглашаться на снижение накопительной части.

Однако, в том самом письме, которое дало толчок этому посту, были такие строки
Так вот, до конца года (до 31.12.13) нужно пойти в районный ПФР с паспортом и пенсионным свидетельством и написать заявление на сохранение процента прежним. <...> Если вам скажут, что не разработана форма заявления, требуйте принять ваше заявление в том виде, в каком вы его напишете, они обязаны его принять. Приблизительный текст может быть таким: «С 01.01.2014 прошу размер отчислений на накопительную часть трудовой пенсии оставить в размере 6%».

Что интересно, прессрелиз пенсионного фонда такой вариант вроде бы подтверждает
Если «молчуны» хотят сохранить накопительный тариф в размере 6%, в течение 2013 года им нужно написать соответствующее заявление в ПФР о перераспределении либо о переводе средств пенсионных накоплений в НПФ или УК.

Давайте думать, хабражители. Давайте думать!

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Ускорение запуска приложений в Linux

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

На примере собранной статистики с утилиты bootchart или подобных можно увидеть количество запускаемых утилит и сервисов при загрузке системы: www.bootchart.org/samples.html

Каждый запускаемы бинарник, обычно динамически, слинкован минимум с glibc, и другими ему нужными библиотеками. По правильной схеме, приложение открывает библиотеку через вызов dlopen(),

<code class="cpp">handle = dlopen("libm.so", RTLD_LAZY);
          if (!handle) {
               fprintf(stderr, "%s\n", dlerror());
               exit(EXIT_FAILURE);
}
</code>

Дальше подключаются функции из libdl.so и поиск нужно библиотеки идет с учетом строк в файле /etc/ld.so.conf, /etc/ld.so.preload, переменных LD_LIBRARY_PATH и LD_PRELOAD и в кэше /etc/ld.so.cache, и некоторых других, зависящих от системы и glibc, условий. Напомню,ld.so.cache формируется утилитойldconfig, с учетом путей указанных в /etc/ld.so.conf. Порядок обхода путей поиска совпадает с последовательностью, указанной в этом файле.

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

<code class="bash"># strace -e open ps

open("/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib64/tls/x86_64/libprocps.so.0", O_RDONLY|O_CLOEXEC) = -1  ENOENT (No such file or directory)
open("/usr/lib64/tls/libprocps.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libprocps.so.0", O_RDONLY|O_CLOEXEC) = 0
open("/usr/lib64/tls/x86_64/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/librt.so.1", O_RDONLY|O_CLOEXEC) = 0
</code>
… итд.

Как видите, библиотеки libprocps и librt нашлись только с третьего раза, выделил жирным. (… почему glibc не использует комбинацию stat+open, не ясно, но не об этом …).
Уже наверно догадались, что для поиска подобных ошибок, мы будем использовать утилиту strace. Не вдаваясь в подробности, strace — отслеживает системные вызовы вызываемой исследуемой программой. У неё есть два, нас интересующих параметра -e c аргументом, имени интересующего нас системного вызова, и флаг -f — отслеживающий системные вызовы у дочерних процессов.
(-ff и -o, но оних позже).

1. Библиотеки
Сама , если это можно так назвать, заключается в подсовывании нужных каталогов нашим бинарникам. Плодить копии одних и тех же библиотек мы не будем, а просто создадим с нужными на каталоги или на файлы с нужными на библиотеками. Из примера выше, мы видим, что приложение в первую очередь ищет в каталоге /usr/lib64/tls/x86_64, которого у нас нет. Нужно его создать, но только на один уровень меньше, т.е /usr/lib64/tls, а в нем ссылку x86_64 на каталог /usr/lib64:

<code class="bash"># mkdir /usr/lib64/tls/ 
# ln -s /usr/lib64/tls/x86_64 /usr/lib64
</code>
посмотрим результат

<code class="bash"># ls -l /usr/lib64/tls/x86_64 

/usr/lib64/tls/x86_64 -> /usr/lib64
</code>
Запустим ещё раз проверку
<code class="bash">$ strace -e open ps

open("/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib64/libprocps.so.0", O_RDONLY|O_CLOEXEC) = 0
open("/usr/lib64/librt.so.1", O_RDONLY|O_CLOEXEC) = 0
</code>
Прекрасно, минус четыре системных вызова и это только с двух библиотек и одного бинарника.

2. Локали.

Аналогичная ситуация с файлами локализаций и локальными настройками LC_CTYPE, LC_MESSAGES и остальные. Эта бяда тянется ещё с лохматых 90-х, по крайней мере в SuSE. Данные файлы и настройки должны лежать в каталоге $LOCALES/$USER_LOCALE (имена условные).
LOCALES — это общая свалка для всех поддерживаемых локалей. В реальности это переменная I18NPATH (у кого в дистрибутиве она установлена? :) (используемые каталоги локалей можно посмотреть командой localedef --help )
USER_LOCALE — это пользовательская настройка, которую можно узнать командой locale.
<code class="bash">$ locale
LANG=ru_RU.UTF-8
LC_CTYPE=ru_RU.UTF-8
LC_MESSAGES=ru_RU.UTF-8
…
</code>
Приложение, если поддерживает локализацию вызывает нужные функции из glibc, которые ищут эти файлы в забавном, но логичном, инкрементальном порядке.

<code class="bash">$ strace -e open ps

open("/usr/lib/locale/ru_RU.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1
open("/usr/lib/locale/ru_RU/LC_MESSAGES", O_RDONLY|O_CLOEXEC) =  -1 
open("/usr/lib/locale/ru/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
</code>
То есть, сначала в /usr/lib/locale/ru_RU.UTF-8, потом в /usr/lib/locale/ru_RU, затем в /usr/lib/locale/ru
Исправляем по предыдущей схеме — создаём ссылку /usr/lib/locale/ru_RU.UTF-8 на каталог /usr/lib/locale/ru

<code class="bash"># ln -s /usr/lib/locale/ru_RU.UTF-8 /usr/lib/locale/ru;
</code>
и скажем glibc, что мы используем ru_RU.UTF-8, а не ru.
(кто не знает как исправить в случае глюков, лучше не делайте)
<code class="bash"># localedef -f UTF-8 -i ru_RU ru_RU.UTF-8;
</code>
и проверим:
<code class="bash">$ strace -e open ps

open("/usr/lib/locale/ru_RU.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/ru_RU.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/ru_RU.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/ru_RU.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/ru_RU.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/ru_RU.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
…
</code>
замечательно, минус по два open на каждый параметр!

3. Пользовательские и графические приложения.
Начнём с классики — xterm. Работает в полном соответствии с POSIX, LSB, X/Open, IEEE, ISO, ГОСТ, DIN :) Лезет в shared library, в локали, локали Xorg и далее специфичные для Xorg/Xfree86 конфиги. Опять же без вникания в суть, Xorg дублирует конфиги, точнее их имена: Но в отличии от glibc, Xorg иногда использует функцию stat()

<code class="cs">$ strace -e open,stat xterm  # (через запятую - список нужны сискалов)

stat("/home/pavel/XTerm", {st_mode=S_IFREG|0600, st_size=333, ...}) = 0 
open("/home/pavel/XTerm", O_RDONLY)     = 4
open("/usr/share/X11/app-defaults/XTerm", O_RDONLY) = 4
</code>
Первый файл это мои настройки, второй — общесистемный.

Тут медаль о двух сторонах, независимо от наличия или отсутствия моего файла, мы получим два системных вызова, но один из них менее ресурсоёмкий — stat(). Получается, если у Вас нет каких-то специфичных настроек для xterm, то лучше выкинуть такие файлы из домашней папки. Это могу быть .Xdefaults-$(hostname), .Xdefaults, .terminfo (файлы со словами auth, лучше не трогать :))
Похожая, но отличная ситуация с курсорами мыши. Если приложение, а это почти все графические, используют библиотеку libXcursor, значит оно будет искать курсоры и иконки сначала в $HOME/.icons/ и затем в/usr/share/icons
<code class="bash">$ strace -e open,stat xterm 

open("/home/pavel/.icons/DMZ/cursors/top_left_arrow", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/pavel/.icons/DMZ/index.theme", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/icons/DMZ/cursors/top_left_arrow", O_RDONLY) = 5
open("/home/pavel/.icons/DMZ/cursors/sb_v_double_arrow", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/pavel/.icons/DMZ/index.theme", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/icons/DMZ/cursors/sb_v_double_arrow", O_RDONLY) = 5
</code>
Просто делаем ссылку с /usr/share/icons на $HOME/.icons и проверяем:
<code class="bash">$ ln -s /usr/share/icons $HOME/.icons
$ strace -e open,stat xterm

open("/home/pavel/.icons/DMZ/cursors/top_left_arrow", O_RDONLY) = 5
open("/home/pavel/.icons/DMZ/cursors/sb_v_double_arrow", O_RDONLY) = 5
</code>

Великолепно, минус 4 опена()!

Далее добавим к strace флаг -f, для отслеживания дочерних процессов.
<code class="bash">$ strace -f -e open,stat xterm
</code>

Вывод очень громоздкий, оставляю вам для изучения в качестве домашнего задания. Скажу лишь, что для многонитиевых приложений лучше делать вывод в файл или даже в отдельные файлы для каждой «дочки».
<code class="bash">$ mkdir /tmp/Xterm (Отдельный каталог для чистоты феншуя)  
$ cd /tmp/Xterm
$ strace -o Xterm.trace -ff xterm 
$ ls 

Xterm.trace.6001  Xterm.trace.6009  Xterm.trace.6017 Xterm.trace.6025  Xterm.trace.6034  
Xterm.trace.6042  Xterm.trace.6050  Xterm.trace.6002  Xterm.trace.6010  Xterm.trace.6018  
Xterm.trace.6026  Xterm.trace.6035  Xterm.trace.6043  Xterm.trace.6051  Xterm.trace.6003  
Xterm.trace.6011  Xterm.trace.6019  Xterm.trace.6027  Xterm.trace.6036  Xterm.trace.6044  
Xterm.trace.6052  Xterm.trace.6004  Xterm.trace.6012  Xterm.trace.6020  Xterm.trace.6028  
...
</code>
изучайте :)

все сразу
<code class="bash">$ egrep "open|stat" ./Xterm.trace.* | grep --color " = -"
</code>
или по одному
<code class="bash">$ egrep "open|stat" ./Xterm.trace.6022 | grep --color " = -"
</code>
Даже сейчас, нашел, что кто-то упорно ищет libreadline.so.6
<code class="bash">./Xterm.trace.28465:open("/usr/lib64/tls/x86_64/libreadline.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
./Xterm.trace.28465:open("/usr/lib64/tls/libreadline.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
./Xterm.trace.28465:open("/usr/lib64/x86_64/libreadline.so.6", O_RDONLY|O_CLOEXEC) = -1 EACCES (Permission denied)
./Xterm.trace.28465:open("/usr/lib64/libreadline.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
</code>

В данном случае косяк в том, что программеры указали явно (специально или через парсер) версию библиотеки. Вместо libreadline.so, захаркодили libreadline.so.6. Исправляем.

<code class="bash">$ cd /usr/lib64/tls/x86_64/
# ln -s libreadline.so libreadline.so.6 
$ cd /tmp/Xterm && rm ./*;
$ strace -o Xterm.trace -ff xterm
$ egrep "open|stat" ./Xterm.trace.* | grep --color "libreadline" 
./Xterm.trace.21278:open("/usr/lib64/tls/x86_64/libreadline.so.6", O_RDONLY|O_CLOEXEC) = 3
</code>

Ура!

Заключение
Для оптимизации KDE, GNOME, Xfce приложений не обязательно настраивать сами менеджеры gdm/kdm/xfwm4, достаточно любого приложения из набора к вашему десктопу, схема работы практически идентичная.

Займитесь в первую очередь всеми бинарниками запускаемыми при загрузке.

Таким способом время загрузки компьютера можно легко уменьшить до 10-15 сек. Время загрузки — это от загрузчика до открытия страницы в фейсбуке, а не появление обоины на экране, как думает Microsoft и Поттеринг.

Потом можно взяться за большие программы Google Chrome, Firefox, Gimp, LibreOffice, etc.

Возможные косяки
Как и в любом деле — важно знать меру, создание ссылок на каталоги может привести к «зацикленным каталогам» и вызов, скажем find ./, может устроить локальный DoS системе. (вроде в ядре уже исправили, но тем не менее ). Года два назад, на SuSE были проблемы при обновлении glibc. Дополнительно рекомендую почитать про TLS (Thread Local Storage)

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Мини-исследование, улучшение и бот для игры Shadow Worlds

Жёлтый заголовок: исследуем MMORPG, добавляем читерских фич и пишем неуловимого бота.
Картинка для привлечения


Что это за игра и что меня с ней связывает

На Shadow Worlds я наткнулся лет 10 назад, и она меня полностью захватила. Мы играли в неё с друзьями по ужасному модемному соединению, мочили крысок и зомбиков, убегали от орков, вскрывали сундучки, радовались победам над боссами и кричали «туууупая игра!» когда умирали из-да дисконнекта.

Что в ней такого особенного, трудно объяснить. Даже по тем временам в ней была достаточно примитивная графика, почти никакого разнообразия, но что-то нас к ней притягивало. Может быть дело в синдроме утенка.

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

Месяц назад, разгребая тонны спама в старом почтовом ящике, я обнаружил письмо от SW Team. В нём говорилось, что недавно запущен новый сервер с новыми картами, предметами и прочими приятностями. В моём мозгу сработал триггер, что пришло очередное время окунуться в ностальгию.
Регистрируюсь, качаю клиент, и вот я в игре.

Первое, что видит каждый новый игрок.

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

Ощутив себя снова молодым, наигравшись, ближе к вечеру воскресенья у меня возникло любопытство: как игра общается с сервером? Ведь, судя по примитивности интерфейса (который я упомяну далее) и отсутствию прогресса за много лет, вполне можно ожидать простоту и в используемом протоколе. Запустил Wireshark, и увидел в логах кашу из байт, ничего осмысленного. Окей, значит будем смотреть изнутри.

Открываю MUDClient.exe, главный ехе-шник игры в IDA, DeDe и OllyDBG. В IDA — чтобы почувствовать себя крутым, в Olly — потому что лучше отладчика не сыскать, в DeDe — потому что игра написана на Borland C++Builder.
Всё проходит на ура, ехе не запакован и не защищён сверху никаким протектором.

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

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


Таким образом, запустив в отладчике MUDClient.exe, он сразу завершается, а вместо него стартует run.exe, да ещё и с запросом администраторских привилегий, и мне приходится вводить админский пароль. Разбираемся.

Открываем в OllyDbg run.exe и ставим точку останова на CreateProcessW. Получаем такое:

Волшебный параметр E8DA81A3FFE9B1. Не будем выяснять, является ли он какой-то контрольной суммой или просто секретом, а возьмём и создадим bat-файл
<code class="dos">start MUDClient.exe E8DA81A3FFE9B1
</code>
Игра запускается, ввод админского пароля не требует, обновляться не пытается. Победка.

Теперь мы можем в Olly указать аргумент командной строки E8DA81A3FFE9B1, игра будет думать, что проверка обновлений не требуется, и мы спокойно можем приступить к отладке. Да и когда просто хочется поиграть, удобнее запустить этот bat-файл. Волноваться о том, что мы пропустим важное обновление не стоит: всё равно в них не бывает свежих ехе-шников, обновляется игра примерно раз в неделю (фишка данного сервера), но обновление содержит только новые файлы игровых локаций.

Чем займёмся? А давайте поохотимся на тех, кто охотится на игроков, то есть на администраторов, которые в игре зовутся Game Master'ами (GM). Их задача отслеживать нарушителей правил, особенно AFK+Macros, то есть когда игрок запускает простенькую программку, которая копает за него руду или рыбачит, а сам уходит по делам. Это запрещено правилами.

Сам я никогда это правило не нарушал (честное слово), и если видел подобное, старался привести к такому игроку зомбиков, а потом обчищал труп. Это весело. Зачем же мне ловить GM'ов? А затем, что проверку довольно легко проморгать если ты на работе, игра на втором мониторе, и ты её случайно перекрыл другим окном, при этом игроки активно троллят друг друга в общем чате. А если то и дело отвлекаться на игру, то работать не получается. Значит надо сделать сигнализацию: как только нас пытаются проверить, посылать какой-то сигнал, например вспупыживать окно игры и мигать им, проигрывать мелодию, высылать СМС.

Как происходит проверка? Администратор телепортируется к тебе, при этом он выглядит как обычный игрок нулевого уровня, только гильдия у него GAME MASTERS, и задает простой вопрос «тут?» или «проверка на afk». Если не последует ответа в течение пары минут, а персонаж продолжает прокачку навыка, значит его нет за клавиатурой и он отправляется в бан.

К отладчику! Входим в игру персонажем Imthebot, потом долго ищем живую душу — в данный конкретный момент в игре онлайн всего 19 человек (не тысяч и не миллионов), что не так мало, бывает и меньше. В итоге натыкаемся на какого-то Bank.

Bank и не подозревает, что он особенный

Быстро хватаем отладчик, пока Bank не сбежал, и осуществляем поиск строки «Bank» по памяти процесса. И находим.


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

Но тут огорчение: довольно скоро на месте этого блока данных появляется мусор, а строка «Bank» обнаруживается уже по множеству других адресов. То есть мы нашли не статичный адрес, что было бы удобно, а просто фантом, продукт жизнедеятельности каких-то процедур. Значит будем искать исток, где эти данные формируются.

Ставим бряк на функции recv в модуле WSOCK32.dll. Происходит множество срабатываний, например, такое:

В буфере, который заполняет recv пока что что-то бессмысленное, как в результатах логирования Wireshark. Поднимаемся по стеку вызовов выше и видим, что в результате обработки одним из call'ов в памяти образуется человекочитаемая строка


Жаль, Bank ушёл по делам

Если продолжить трассировку, окажемся в ядре системы. Дело в том, что вызов recv осуществляется в потоке, задача которого сформировать строку в памяти, а её потом заберёт и обработает главный поток игры. Можно поставить hardware breakpoint на сформированную строку и оказаться в обработчике главной нити.

Некоторое время, сидя на работе, я развлекался тем, что логировал приходящие сообщения в файл средствами OllyDbg. Делается это установкой условной точки останова (Shift+F4)


В результате у меня формировались гигантские портянки данных.
Пример портянки, когда мимо прошёл игрок Zloy0042A8CC New thread with ID 00000418 created
0044A435 COND: 0:448:P222:Imthebot:1014:46:133:1000:1000:0:0:0:0:0:0:;G0000000
Thread 00000418 terminated, exit code 4BDFF7C (79560572.)
0042A8CC New thread with ID 000007F0 created
0044A435 COND: 0:448:P212:Imthebot:1014:47:133:1000:1000:0:0:0:0:0:0:;G0000000
Thread 000007F0 terminated, exit code 4BDFF7C (79560572.)
0042A8CC New thread with ID 00000288 created
0044A435 COND: 0:493:P322:Imthebot:1014:48:134:1000:1000:0:0:0:0:0:0:;P610:Zloy:1009:56:138:1000:1000:0:0:0:0:0:0:;G0000000000
Thread 00000288 terminated, exit code 4BDFF7C (79560572.)
0042A8CC New thread with ID 000009B0 created
0044A435 COND: ???
Thread 000009B0 terminated, exit code 4FFFF7C (83885948.)
0042A8CC New thread with ID 000008E0 created
0044A435 COND: 0:493:P222:Imthebot:1014:50:134:1000:1000:0:0:0:0:0:0:;P620:Zloy:1009:55:138:1000:1000:0:0:0:0:0:0:;G0000000000
Thread 000008E0 terminated, exit code 4FFFF7C (83885948.)
0042A8CC New thread with ID 000007A0 created
0044A435 COND: Ok

0044A435 COND: 0:493:P202:Imthebot:1014:50:134:1000:1000:0:0:0:0:0:0:;P710:Zloy:1009:54:137:1000:1000:0:0:0:0:0:0:;G0000000000
Thread 000007A0 terminated, exit code 4FFFF7C (83885948.)
0042A8CC New thread with ID 00000C3C created
0044A435 COND: ???
Thread 00000C3C terminated, exit code 51FFF7C (85983100.)
0044A435 COND: Ok



И вдруг мне в персональный чат приходит сообщение от пользователя GM с текстом «GM-GM — check for AFK // ГМ — проверка на АФК». При этом рядом со мной никого не было. Я аж подпрыгнул от неожиданности. Поприветствовав таинственного GM я полез на форум и обнаружил свежайшую тему, в которой говорилось о реформе GM-проверок. Коротко: теперь GM не прилетает к тебе, а вводит специальное заклинание, в результате чего он начинает видеть персонажа, но не знает кто перед ним — ни ник, ни уровень, ни даже внешний вид определить нельзя. Видны только действия которые ты совершаешь и противники рядом (которые заменены на мышек для большей анонимности). Таким вот образом решалась проблема нечестных гейм мастеров.

Это был дополнительный вызов: мало того, что надо отслеживать игроков рядом с собой, так ещё и персональный чат. Вопрос от GM, который мне прилетел, попал в лог, вот он:
0044A435  COND: 48:457:01GM-GM - check for AFK // ГМ - проверка на АФК;I41:46:35;P002:Imthebot:1001:53:35:1000:1000:0:0:0:0:0:0:;G00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Пора писать патч. Что от него требуется? Он должен передавать строку, которая прилетает с сервера, в моё внешнее приложение, которое уж разберётся, что с ней делать. Для этого буду использовать посылку сообщения WM_COPYDATA моему окну.

Быстрое гугление дало такой код:

<code class="cs">var
   aCopyData: TCopyDataStruct;
   hTargetWnd: HWND;
begin
   with aCopyData do
   begin
     dwData := 0;
     cbData := StrLen(PChar(Edit1.Text)) + 1;
     lpData := PChar(Edit1.Text)
   end;
   // Search window by the window title 
  // Fenster anhand des Titelzeilentext suchen 
  hTargetWnd := FindWindowEx(0, 0, nil, PChar('WM_COPYDATA-Receiver'));
   if hTargetWnd <> 0 then
     SendMessage(hTargetWnd, WM_COPYDATA, Longint(Handle), Longint(@aCopyData))
   else
     ShowMessage('No Recipient found!');
end;

</code>

В импорте MUDClient.exe нет функции FindWindowEx, зато есть FindWindowA, поэтому буду пользоваться ей.

Прыжок на патч будет в этом месте:

Здесь есть сформированная строка, и три NOP пойдут на пользу

Я просто запишу поверх трёх завершающих команд в процедуре свой «JMP 00515080»
При этом следует помнить, что съев две команды POP, мы должны их восстановить.

Патч-ретранслятор, который я разместил в большом блоке памяти заполненном нулями, выглядит так:


Код приёмника ещё проще:

<code class="cs">procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;

------

procedure TForm1.WMCopyData(var Msg: TWMCopyData);
begin

  try

  StrLCopy(sText, Msg.CopyDataStruct.lpData, Msg.CopyDataStruct.cbData);

  DoProcessNewLine(sText);  //можно обрабатывать её как мы хотим

  except end;

end;

</code>

Не патч, а лоадерНа самом деле, ехе-файл я не изменяю. Вместо этого, моё приложение запускает MUDClient.exe и с помощью команды WriteProcessMemory модифицирует код в памяти. Это позволяет распространять «бота» в виде одного ехе, а не двух, а ещё позволяет избежать нарушения пункта в лицензионном соглашении (Grammar Nazi, к бою)
13. Вход в игру через старый клиент, а так же любая модификация exe-файла игры.


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


Выше приводил часть строки, в которой было сообщение в приват от персонажа GM.

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


Типичный пример нарушения правил. Качает щит на мышках AFK, и даже не обратил внимание, что я попортил одной из них здоровье
Продолжение в картинках







Правда, весело?


Раз уж исследовал приём данных с сервера, надо бы поглядеть хоть одним глазком, что клиент передаёт со своей стороны. Не стану обременять читателя листингами, расскажу вкратце, что точно так же как с recv, я поставил брейкпоинт на send, поднялся по стеку вызовов и нашёл место, где строка ещё не закодирована. Примеры команд:

VR — шлётся непрерывно, этим клиент говорит о том, что он жив и хочет обновить состояние
QR — выход персонажа из игры
UI4:0 — использовать 4 ячейку инвентаря. Например, выпить бутылочку, съесть рыбу, прочитать свиток
MB012:4:0 — переместить предмет инвентаря из 12 ячейки в 4
ACПривет0000 — сказать «Привет» в локальный чат
PC*Vasya*Привет — написать «Привет» в приватный чат игроку Vasya
SP3 — сесть (когда персонаж сидит, у него быстрее восполняется здоровье и магическая энергия)
ACesani gre olam1003 — прочесть заклинание огненного шара на персонажа с ID1003

и так далее.

Каждая команда обязательно завершается символами 0x13 и 0x10

Как этим воспользоваться? Подделывать команды, конечно же. Можно написать более удобный чат, научить персонажа автоматически съедать рыбу, автоматически садиться. Конечно, многое можно сделать эмуляцией нажатий клавиш и кликов мышкой. Многое, но не всё.

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

Тут можно рассказать про казусПока я тестировал новый патч, мне написал друг «слушай, это не ты там балуешься?». Я не понял его вопрос, а потом обратил внимание на глобальный чат, в котором игроки массово возмущались перезапуском сервера. При этом их выкидывало из игры, происходил небольшой откат игрового состояния, и все мобы, включая боссов, появлялись заново. Я не поверил сначала, но сделал несколько проверок, и в результате одной сервер рестартовал. В чате началась полная истерика, но винили все какого-то Elf (если не перепутал ник) и просили его прекратить безобразие. Не знаю почему Elf стал козлом отпущения, то ли он заслужил славу местного хакера, то ли потому что он параллельно админит игру и помогает себе используя служебное положение, а потому имеет дурную славу. Не знаю.

В общем, я сделал в своей проге кнопку «уронить сервер», которую потом ещё пару раз успешно проверил (потому что не верил, что уронить сервер так просто), что нас с другом весьма веселило «кто-то держит этот сервер за яйчишки». А через несколько часов она перестала работать, видимо, залатали на сервере ошибку, и это хорошо, так как я написал в личку главному админу письмо, в котором признался, что это был я, как я это сделал, и вообще какими делами я занимаюсь, но перед нажатием «отправить», решил проверить последний раз и… обнаружил, что сервер не сломался.

Да, дело было в том, что я не завершал команды завершающей последовательностью 0x13 0x10.


Из прикольного. В игре есть возможность «посмотреть» на персонажа рядом, для этого надо щёлкнуть по нему с зажатым ALT.


Любопытно, что за команда отсылается при этом. Щёлкнем по самому себе, в логе отобразится такое:
<code class="dos">00515160   COND: ID1006
</code>
Попробуем изменить 1006 на 1001, получаем


А ведь этот игрок не просто не рядом с нами, и даже не в другой локации, а вообще в другом мире (куда уходят все, кто прокачался до 21 уровня, так как в первом мире дальше опыт не идёт).
Это даёт возможность знать, кто сейчас онлайн. Но стоп, ведь список игроков онлайн доступен на сайте игры. Это так, но в нём не видны администраторы. Также, для сокрытия админов, при попытке послать им в приват сообщение, даже если админ онлайн, отобразится «не удалось отправить сообщение», как если бы он был не в игре. А благодаря найденной возможности, мы можем всегда знать, что тот или иной GM сейчас работает. Задача облегчается тем, что достаточно делать перебор с ID1000 до… ID1100, чего хватит за глаза. Когда кто-то выходит из игры, и освобождает ID, следующий игрок забирает ID себе. Таким образом, нам не надо угадывать ID гейм мастера. И в качестве бонуса мы можем следить за состоянием здоровья любого игрока, даже если он от нас убежал.

Например, пошлю команды
<code class="dos">ID1020
</code>
Результат:
<code class="dos">Osiris:0:Invictus:53:0:705:705:1:124:190:189:0:139:187:131:184:186:0:0:0:
</code>

<code class="dos">ID1021
</code>
Результат:
<code class="dos">Admin:0::80:0:1880:1880:0:0:136:555:171:138:167:133:155:163:0:0:0:
</code>

Довольно вкусно.

Инвентарь

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

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

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


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

Начиная с 00550AC4 хранятся четырёхбайтовые значения, которые определяют предмет. Правда, просто взять и сопоставить эти значения изображениям в папке tga/items, не получилось. Рука зомби, как мы видим, имеет индекс 151, но в папке с картинками руке соответствует другое значение.


Простым вычитанием 151-149 не отделаться, так как для других предметов разница может быть совсем другой.

Открываем в WinHex файл ITEMS.DAT, который лежит всё в той же папке tga/items.


Как видим, он не похож на зашифрованный, хоть на первый взгляд из полезного в нём только описание предметов на русском и альтернативном языках (в немецкой версии будет немецкий). Немного копошимся в файле чтобы найти какую-то структуру, и находим довольно быстро: если посчитать расстояние между началом каждого описания предмета в байтах, то оно каждый раз равно 0x2E2 (738) байт. То есть каждый блок информации об N-предмете начинается с 738*N.

Но что такое 151, который соответствует руке зомби? Очень просто: умножаем 151*738, отступаем от начала файла на эту величину (0x1B34E) и видим:

Как из этой информации получить название графического файла, в котором нарисована рука? Лично я увидел глазами, но можно и воспользоваться поиском по значению, что по адресу 1B5A4 лежит искомое 149 (149.bmp000.png). Вывод: через 0x256 байт от начала блока данных идёт число 2 байта, равное номеру PNG файла с картинкой.

Инвентарь почти готов. Но простого отображения мало, надо ещё использовать предметы из него. Как мы выяснили ранее, если послать серверу команду UIX:0, где Х это номер ячейки, предмет будет использован. Теперь можно бегать своим магом и пить бутылки маны на ходу, воином пить бутылки восполнения здоровья, не открывая внутриигровой инвентарь, а тем более неудобный «быстрый».

Как ловить рыбуОдна из мирных профессий в игре это рыбак (он же кузнец, но это не важно). Нужен он не просто для ловли рыбы, а магической рыбы «магички». Обычно ловля автоматизируется макросом, который щёлкает правой кнопкой по рыболовной сети, а потом левой кнопкой мыши по водоему. Магичка ловится редко, в основном попадаются бесполезные мелкие рыбёшки, которых надо съедать (это прокачивает навык лечения). Наловишь полный рюкзак рыбы, а потом нудно щёлкаешь по ненужным рыбёшкам, оставляя магичек.

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

Немного технического извращения: если просто послать серверу команду UIX:0, он действительно её съест, и даже пошёл клиенту «OK», вот только клиент понятия не имеет, к чему этот OK относится, ведь он ничего не посылал, и проигнорирует его. Поэтому клиент будет продолжать думать, что рыбка/бутылочка всё ещё цела. Решил проблему очень грубо: после отсылки команды UIX:0 надо записать при помощи WriteProcessMemory в соответствующую ячейку нули. И рыба сразу пропадёт.


Для большей функциональности инвентаря осталось сделать элементарное: при клике по предмету «нашего» инвентаря, быстрый инвентарь игры должен прокручиваться на этот предмет, а двойной клик передаваться в игру. Тоже было сделано элементарно: ArtMoney нашел адрес по которому хранится позиция быстрого инвентаря, и старой доброй WriteProcessMemory пишу туда нужное мне число. Двойной клик посылается командой
<code class="cs">PostMessageW(h, WM_LBUTTONDBLCLK,wParam,lParam);
</code>

Никогда ещё работа с инвентарём в Shadow Worlds не была такой удобной, скорость выбрасывания предметов (очень полезно рудокопам) увеличилась в разы, я почувствовал себя изобретателем рычага и колеса.

Авто исчезновение и бан

Немного скучных соплей и внутриигровых перипетий
Сделав свою прогу весьма функциональной, я отвлёкся от неё, и увлёкся игрой. С другом стали качать кузнецов — в рабочее время на них не надо особенно отвлекаться: копай себе руду, потом изредка куй из неё простые предметы, а прога упрощала взаимодействие с интерфейсом.

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

Беда вторая, наши. Русские игроки высоких уровней сначала нас не трогали, так как пытались воевать с «америкосами», как их зовут на сервере, хотя там не только американцы. Но очень скоро иностранцы заняли доминирующее положение, а «наши» поняли, что противопоставить сильной гильдии ничего не могут, и стали отрываться на нейтральных персонажах новичков. Попытки договориться ни к чему не приводили — им в кайф было нас (новичков) мочить, в ответ на вопрос «зачем?» только неадекватная нецензурщина. Администрация же никак регулировать вопрос не хотела — «это PvP-сервер», таков их ответ. В моём понимании, PvP это когда у игроков дуэль. А то, что происходило в шахтах — просто живодёрство.

Возникла дилемма: либо перестать играть, либо найти способ выживания. И я решил, что выбора нет, и пошёл на нарушение пункта правил
8. Использование [...] программ использующих автоматический процесс входа/выхода персонажа из игры, багов игры.


Итак, пишем автоматизацию выхода из игры в случае опасности. Для этого имеется всё необходимое: как только появляется персонаж на экране, мы получаем извещение об этом. Сделать выход из игры можно минимум двумя способами: послать команду QR на сервер, или же проэмулировать нажатие мышкой на кнопку «выход». Нажимать надо быстро, так как если персонажа один раз ударят, в течение минуты он должен оставаться в игре.

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

Ещё мне пришла в голову преступная мысль (только ради науки): сделать полностью автоматического Imthebot, который будет рыбачить или копать руду, при этом избегать опасностей и отвечать на простенькие вопросы GM'ов. Сколько дней/месяцев он бы продержался, какой уровень навыков бы смог прокачать? Несколько дней я вынашивал идею, но отказался, так как моё увлечение прокачкой кузнеца было слишком сильно, и не хотелось тратить время на «глупости».

И тут случилось ужасное: как всегда я копал руду, и ко мне телепортировался Admin. Сработал автовыход, я тут же быстро нажал «войти» и поздоровался. Но было поздно

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

Ох, как же я себя корил за то, что вовремя не добавил Admin в белый список, ведь постоянно думал на эту тему, но руки не доходили. Я попытался поговорить с админом, но натолкнулся на стену молчания. Похоже, он уже привык к нытью тех, кто забанен. После долгих приглашений к диалогу он только добавил, что «на вас поступила жалоба, я проверил, и подозрение подтвердилось». Забавная жалоба: не могу убить своим крутым магом/воином голого ремесленника низкого уровня, поэтому попрошу админа разобраться.

Потеря кузнеца стала для меня очередной логической точкой «тууууупая игра», после которой игра вновь перемещается в воспоминания.

Немного правды и рассуждения о добре и зле

Очевидны вопросы: не пострадает ли игра после статьи, не нахлынут ли читеры и багоюзеры? Нет. Во-первых, конкретного кода в статье почти нет, одни идеи. Во-вторых, все эти идеи не совсем актуальные, то есть они будут работать, но коряво. К примеру, код, которым я подделываю команды, уходящие на сервер, нестабилен. Так как он перетирает нормальные запросы клиента, через какое-то время клиенту становится дурно, и происходит дисконнект. Как делать правильно, я не буду рассказывать — статья от этого лучше не станет. Улучшение алгоритма автовыхода также никому ничего не даст: админ легко может создать другого персонажа для проверки, и месяцы прокачки пойдут в null, ибо админы весьма суровы — никакой демократии и презумпции невиновности.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Идеальная миграция на примере Catch-&gt;Evernote

Помним, скорбим.
Сегодня мы первый день без Catch.com.

Так нельзя

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

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

К моменту извещения о своей гибели Catch наконец улучшил свой экспорт (и на том спасибо), который до этого работал кое-как и через раз. Но вариантов импорта в Evernote оставалось немного — качаем архив экспорта с Catch.com, ставим Evernote desktop, распаковываем архив (одновременно обнаруживая что заметки с русским заголовком в Windows не распаковываются на диск), после чего делаем импорт в Evernote enex-файлов. Результат: или оказываемся с потерянными вложениями и тегами, или изобретаем костыли, или получаем кучу ручной работы.
Хабр уже пестрил ветками обсуждений альтернатив, но элегантных вариантов бегства на основного конкурента Catch не было видно.

Как надо

В ходе курения форумов удалось наткнуться на ветку discussion.evernote.com, где некий davious буквально за несколько дней до этого выложил полноценный скрипт импорта на питоне. Выступать в режиме beta-тестера не всегда приятно, но, как выяснилось, не сегодня.

Оцените сами всю красоту этого не побоюсь сказать небольшого произведения. Во всяком случае я уже не вспомню когда последний раз натыкался на что-либо подобное касаемо миграции:
  • распаковывать архив Catch не требуется(!), скрипт залезает в него сам;
  • корректно импортируются все заметки, включая русский язык — проверено;
  • корректно импортируются все теги — проверено;
  • корректно импортируются все вложения и изображения — единственный глюк это то что перестает работать поворот изображений, видимо какие-то недоработки с exif-метками;
  • в ходе импорта в командной строке выводится подробный прогресс процесса (что немаловажно, т.к. процесс занимает до нескольких часов для больших блокнотов);
  • обрыв соединения и повторный запуск обрабатываются штатно, дублей не возникает;
  • документация к скрипту достаточно подробная, хотя и имеет несколько недоговорок по настройке.
Наконец, это работает всё не через какие-то костыли, а при помощи developer token от Evernote.

Никогда процесс экспорта-импорта еще не был так приятен.
Export results: Completed 'Main' Notebook upload: uploaded 639 notes, 351 attachments, 727 tags.

Успели скачать экспортный файл Catch.com, но еще не решили где его применить? Надеюсь это вам поможет.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Юбилей Google Chrome — 5 лет

Небольшой, но уже значимый по масштабам достижений, юбилей браузера Google Chrome, который, кажется, не заметили в самой Google: 2 сентября 2008 года поисковый гигант анонсировал выпуск собственного браузера на базе открытого проекта Chromium и выпустил первую публичную бета-версию Chrome на 43 языках. Официальный блог-пост по этому поводу можно прочитать здесь. В частности, Сандар Пичай (Sundar Pichai) — руководитель проекта Chrome, сейчас в Google он занимается Android — написал буквально следующее:
Мы поняли, что веб эволюционировал от преимущественно простых текстовых страниц к насыщенным интерактивным приложениям и нам надо было полностью переосмыслить браузер.
Ориг.We realized that the web had evolved from mainly simple text pages to rich, interactive applications and that we needed to completely rethink the browser.


Разные аналитические агенства считают популярность браузеров по-своему, колеблясь кому же отдавать первенство на рынке: к примеру StatCounter считает Chrome первым и приписывает его аудитории в 300 млн человек или около 43% рынка. Интересно, что к моменту своего появления, детищу Google пришлось бороться с 72%-й долей Internet Explorer и 20%-й другого свободного проекта — Mozilla Firefox.

Среди основных причин популярности Chrome (есть мнение, что только за 1 день после релиза беты браузер мигом набрал около 1.5% аудитории) называют минималистичный «плоский» интерфейс (в самой компании говорят «clean and fast»), быстрое обновление (раз в шесть недель — в связи с этим индекс стабильной версии Chrome достиг уже 29) и поддержку целого стека новейших технологий, таких как HTML5, CSS3, новейшие JavaScript APIs, WebRTC и WebGL.

Как известно, развитие браузера не остановилось — в апреле этого года Chrome переехал на собственный движок Blink. Ещё раньше Chrome «стал» операционной системой, полностью ориентированной на работу в Интернете — Google Chrome.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Криптопереписка для недоверчивых

Осторожно: данный пост может вызывать непродолжительное обострение паранойи

Привет! Не верите ли вы в популярные продукты для защищённой переписки так, как не верю в них я? Например, в браузерные крипточаты с шифрованием на стороне клиента, или в p2p-криптомессенжеры?

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

image



Вступление

Во всех продуктах защищённой коммуникации, которые я встречал, у меня неизбежно возникал вопрос доверия их разработчикам. Я не понимал, почему, скажем, к автору продукта всё ещё не пришли и не попросили ослабить шифрование или отдавать клиенту с определённым ip-адресом особый javascript-код. Вы можете сказать: «это невозможно». Почитайте, например, недавний пост Почтовый сервис Lavabit вынужден закрыться, и, особенно, продолжение этой истории(англ.), прошедшее мимо хабра.

К сожалению, люди совершают ошибки. Взять, например, сервис, первый по ссылке гугла по запросам «secure chat» и «crypto chat», который называется Cryptocat. Примерно три месяца назад в его коде обнаружилась ошибка — из-за недостаточно хорошей реализации генератора случайных чисел групповые сообщения, которые передавались в период с 17 октября 2011 года по 15 июня 2013 года стало возможно расшифровать, см. Decryptocat. Причём, в начале 2013 года компанией Veracode проводился аудит кода, который присудил ей «Security Quality Score of 100/100», и это был не единственный аудит кода в этот период.

Поэтому возникла идея использовать для коммуникации библиотеки, открытые алгоритмы и протоколы с более чем десятилетней историей поиска уязвимостей. Для меня, как и, надеюсь, что для многих из вас — это алгоритмы и протоколы из openssl и openssh(который, кстати, использует openssl внутри), а именно: TLS, SSH, SHA1, AES256, RSA и D-H. Я буду рассказывать на их примере, но, конечно, вы можете заменить их на те, которым доверяете лично вы, основная идея при этом не изменится.

Об OpenSSL

OpenSSL — библиотека с открытым исходным кодом, реализующая протоколы SSL/TLS. Они используются каждый раз, когда вы заходите на сайт по HTTPS. Про это недавно была статья.

Вот список уязвимостей, которые нашли в OpenSSL за более чем 10 лет анализа.

Неполный список программ, которые используют OpenSSL: apache, nginx, squid, openvpn, openssh, ntp, dhcp, cups, syslog-ng, xorg-server, php, python, ruby, libevent, nodejs, curl, wget, links, lynx, socat, hostapd, wpa_supplicant, virtualbox, vmware-player, libreoffice, ffmpeg.

И совсем немного про TLS. TLS — это криптопротокол, который позволяет устанавливать защищённые соединения. Сейчас существуют 3 версии этого протокола: 1.0, 1.1 и 1.2. Они описаны, соответственно, в rfc 2246, rfc 4346 и rfc 5246. Забавно, что все они заканчиваются на 46. Мы будем использовать версию 1.0 т.к. она вышла в 1999 году и в ней не было найдено серьёзных уязвимостей.

Протокол очень хитрый. Очень упрощённо процесс выглядит так: стороны договариваются о ключе для симметричного шифрования и в дальнейшем его используют. Все сообщения защищаются от изменения/подмены при помощи сочетания хэш функции с секретным ключём(HMAC). Также в протоколе предусмотрена взаимная аутентификация сервера и клиента

Помимо полной реализации TLS, библиотека OpenSSL содержит множество криптографических и математических алгоритмов и имеет консольный интерфейс.

Примеры использования1) Тестирование чисел на простоту:
<code class="bash">$ openssl prime 997
3E5 is prime
</code>
2) Генерация случайных чисел:
<code class="bash">$ openssl rand -hex 16
2871002e6f3cff937d066da9d3017197
</code>
3) Вычисление контрольной суммы:
<code class="bash">$ openssl sha1 /etc/passwd
SHA1(/etc/passwd)= 8b74a9f1ddf496c02bc85e0e120bbb903d922276
</code>
4) Шифрование:
<code class="bash">$ openssl aes-256-cbc -k pass -in /etc/passwd
<много бинарного вывода>
</code>

Именно этот интерфейс мы и будем использовать для нашей задачи. Перейдём к делу.

Простой вариант

Первый собеседник (с «белым» ip, назовём его «сервер») выполняет:
<code class="bash">openssl s_server -accept 4433 -nocert -cipher ADH-AES256-SHA -tls1 -no_ticket
</code>

Второй собеседник, клиент, выполняет:
<code class="bash">openssl s_client -connect <host>:4433 -cipher ADH-AES256-SHA -tls1 -no_ticket
</code>

Что мы только что сделали? Первой командой мы запустили tls 1.0-сервер, а второй — подключились к нему. Теперь можно общаться, все сообщения шифруются алгоритмом AES256, ключ для шифрования согласуется с помощью алгоритма Диффи-Хеллмана(D-H). Вот отличное пятиминутное видео, объясняющее его суть. Алгоритм D-H позволяет получить общий секретный ключ, используя незащищённый от прослушивания канал связи.

На этом можно было бы и закончить, но у такого подхода есть три проблемы:
1) Он не защищает от атаки «человек посередине»(MITM, Man In The Middle). Идея атаки тривиальна — становимся между сервером и клиентом, клиент думает, что подключается к серверу, а на самом деле, подключается к нам(к злоумышленнику), а мы транслируем его трафик на настоящий сервер.
2) Требуется наличие белого ip хотя бы у одной стороны.
3) Даже если данные нельзя расшифровать, доступна «метаинформация» о соединении: кто с кем соединялся, когда и сколько данных передано.

Защищаемся от MITM

Для того, чтобы защититься MITM, нужно, чтобы сервер аутентифицировал клиента, а клиент — сервера. Это достигается использованием асимитричного шифрования.

На на сервере и на клиенте нужно сгенерировать закрытый RSA-ключ и публичный сертификат.

На сервере выполняем:
<code class="bash">openssl genrsa -out server.key 2048
openssl req -new -key server.key -batch -days 3650 -x509 -out server.crt
</code>

На клиенте:
<code class="bash">openssl genrsa -out client.key 2048
openssl req -new -key client.key -batch -days 3650 -x509 -out client.crt
</code>

Здесь, 2048 — количество бит в модуле закрытого ключа, 3650 — срок действия сертификата в днях.

Затем сервер должен передать свой сертификат(файл server.crt) клиенту, а клиент(файл client.crt) — серверу. Это слабое место, ведь злоумышленник может подменить сертификат в момент передачи(если он его просто прочитает, то ничего страшного). Поэтому, лучше передавать его, используя несколько каналов(pastebin, email, skype, jabber, sms, голосом по телефону, почтой России, стеганографией в фотографиях котят в блоге, и.т.д). Передать сертификат достаточно один раз.

После этого, команда для создания TLS-сервера будет выглядеть так:
<code class="bash">openssl s_server -accept 4433 -cert server.crt -key server.key -Verify 0 -CAfile client.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket
</code>

Подключение к серверу:
<code class="bash">openssl s_client -connect <host>:4433 -cert client.crt -key client.key -verify 0 -CAfile server.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket
</code>

Теперь сервер и клиент смогут аутентифицировать друг друга.

Важно: если аутентификация прошла не успешно, то ни сервер, ни клиент не разорвёт соединение! Они лишь напишут об ошибке. К сожалению, нет ключа, который бы менял это поведение, поэтому нужно внимательно смотреть в лог подключения. Ошибка выглядит примерно так:
<code class="bash">verify error:num=18:self signed certificate
</code>

Будем считать, что проблему MITM мы решили, осталось понять как решить проблемы 2) и 3). Здесь нам поможет протокол SSH.

SSH спешит на помощь

Протокол SSH активно используется при администрировании UNIX-серверов. Он чем-то похож на TLS, передаваемые данные тоже шифруются и подписываются. О ключе для шифрования договариваются обе стороны, например, используя тот же алгоритм D-H.

Для того, чтобы осуществить наш коварный план по защищённому обмену информацией, нам понадобится сервер с доступом по SSH и с белым IP. Найти такой сервер в наши дни не составляет особой сложности. Лучше искать тот, к которому подключаются много и часто.

Одна из особенностей протокола — он позволяет создавать защищённые туннели. Этим мы и воспользуемся!

На сервере выполняем:
<code class="bash">ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -R 4433:127.0.0.1:4433 user@sshhost
nc -l -p 4433 -v
</code>

Здесь, для дополнительного спокойствия, мы явно указываем алгоритмы шифрования, обмена ключами и хэширования. Ключ -R значит, что все подключения на порт 4433 ssh-сервера пойдут в шифрованный ssh-туннель и попадут к ssh-клиенту на тот же самый порт. Если у пользователя установлен в качестве шелла /sbin/nologin, то иногда помогает использование ключа -N, который указывает ssh-клиенту, не исполнять никаких команд на сервере, а лишь только создать туннель.

На клиенте выполняем:
<code class="bash">ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -L 4433:127.0.0.1:4433 user@sshhost
nc 127.0.0.1 4433
</code>

Теперь, если клиент подключится к себе на 127.0.0.1 на порт 4433, то ssh-клиент запроксирует соединение по защищённому туннелю на порт 4433 удалённой машины, а оттуда, данные перешифруются и полетят по другому туннелю на машину-сервер.

Команда nc — это вызов популярной утилиты netcat. Она позволяет слушать и устанавливать tcp-соединения, а так же передавать по ним данные. При выполнении команд выше, стороннему наблюдателю будет казаться, что никакого туннеля нет и что это просто два ssh-подключения к одному и тому же серверу, никак не связанных между собой. Таким образом, получаем защищённое и относительно незаметное соединение.

Что плохо? То, что мы не можем доверять ssh-серверу! Теоретически он может писать расшифрованные данные к себе в лог в момент их перешифровки, когда они попадают из одного туннеля в другой.

SSH + OpenSSL или We have to go deeper

Теперь пустим наш TLS-трафик поверх цепочки SSH-туннелей. Если вы внимательно следили, то итоговая последовательность команд будет такой:

На сервере:
<code class="bash"># следующие три строки обязательны только для соединения в первый раз, в дальнейшем - опциональны
openssl genrsa -out server.key 2048
openssl req -new -key server.key -batch -days 3650 -x509 -out server.crt
[передаём server.crt клиенту]

ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -R 4433:127.0.0.1:4433 user@sshhost

openssl s_server -accept 4433 -cert server.crt -key server.key -Verify 0 -CAfile client.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket

[ждём соединения]
[внимательно смотрим на лог подключения на предмет ошибок валидации сертификата]
[общаемся]
</code>

На клиенте:
<code class="bash"># следующие три строки обязательны только для соединения в первый раз, в дальнейшем - опциональны
openssl genrsa -out client.key 2048
openssl req -new -key client.key -batch -days 3650 -x509 -out client.crt
[передаём client.crt серверу]

ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -L 4433:127.0.0.1:4433 user@sshhost
openssl s_client -connect localhost:4433 -cert client.crt -key client.key -verify 0 -CAfile server.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket

[внимательно смотрим на лог подключения на предмет ошибок валидации сертификата]
[общаемся]

</code>

Для того, чтобы ssh-клиент уходил в background после подключения, ему можно указать ключи -Nf.

Итог


Итак, не написав ни одной строчки кода и используя только стандартные инструменты, мы получили возможность переписываться, используя незаметное, способное работать за NAT'ом, соединение, защищённое от прослушивания, MITM-атак и подмены сообщений. К тому же, оно относительно просто для настройки — от каждого собеседника требуется выполнить всего по 4 команды и одну передачу файла для первого соединения, и по две команды для последующих. Да, ещё требуется доступ по SSH к любому серверу.

MiniFAQ

Q: Почему не VPN?
A: VPN — хорошее решение. Но он сложен в настройке, требует рутовых прав на сервере или доверия к серверу.

Q: Почему не GnuPG?
A: GnuPG — тоже хорошее решение. Но при желании переданные ранее данные можно расшифровать, получив закрытый ключ(например, вместе с ноутбуком).

Q: С чего вы взяли, что в OpenSSL нет уязвимостей?
A: Я уверен, что они там есть. OpenSSL лично мне субъективно кажется надёжным, поэтому я рассказывал на его примере. Можно использовать любую другую реализацию, которой доверяете лично вы.

Q: Обещаете ли вы, что команды правильные?
A: Не обещаю! Советую проверить!

Q: Как дела с кроссплатформенностью?
A: OpenSSL — кроссплатформенная. Клиенты SSH существуют под большинство ОС.

Q: Хочу веб-интерфейс, почему консоль?!
A: Для вэб-интерфейса требуется писать код. Одна небольшая XSS-уязвимость может стоить важных данных. Моя логика проста: нет кода — нет ошибок.

Q: Ошибка getaddrinfo: Name or service not known при выполнении команды openssl s_server
A: У вас, наверно, выключен IPv6. Обновите openssl.

Q: Ошибка gethostbyname failure при выполнении команды openssl s_server
A: Проверьте файл /etc/hosts. Первое имя для адреса 127.0.0.1 обязательно должно резолвиться.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Если бы языки программирования были детскими конструкторами



Всем привет! Как то случайно года 3 назад представил язык Pascal как детский конструктор, и написал об этом заметку. Показал друзьям, они заценили. Позже добавил C#, C++, HTML и Ассемблер. Надеюсь, хабровчанам понравится. Приятного чтения!

Pascal
Представляет собой железный конструктор в серой невзрачной коробочке. Детали бывают трех видов — длинные но узкие, короткие но широкие и уголком. Скрепляются между собой винтиками. Если в детали есть 3 места, в которые можно вкрутить винтик — то надо их туда вкрутить, даже если винтики ничего не будут держать! Иначе вся конструкция сразу развалится.
Приведены несколько примеров для творчества — маленький дом, средний дом, большой дом и почему то подобие вертолета. Невероятно, но вертолет сможет даже летать.
Все, абсолютно все модели строятся по одному плану — снизу фундамент, сверху крыша, посредине пустой каркас. А вот внутрь каркаса можно запихнуть абсолютно все, хотя это и не вяжется с современными концепциями конструирования. Но всегда можно представить что две рейки это лифт большого дома, а три рейки это двигатель вертолета! Все как по настоящему!
В Паскале даже можно иногда использовать веревочки — это позволит создавать гибкие динамические конструкции. Для этого надо собрать железный короб, жестко его закрепить и в него положить веревочку.
Опытный паскалист, вспомнив молодость, сделает на Паскале абсолютно все.
Известный Р. Столлман собрал из Паскаля коробку с конструктором С.
Паскаль устаревший конструктор, поэтому его не жалко поломать и его дают играть детям и студентам младших курсов.

С++
Купив С++ вы думаете что купили конструктор, но на самом деле это целый ремонтный набор. К основной коробке потом можно будет отдельно докупить множество больших и маленьких коробочек с детальками сложной формы, которые очень упрощают жизнь.
С++ это весьма сложный конструктор, для его использования надо сначала прочитать инструкцию на обратной стороне коробки. Если этого окажется недостаточно, можно выписать по почте полный сборник инструкций из 10 томов по 600 страниц в каждом.
Некоторые собирают табуретки. Другие хвастаются что собрали работающий разводной гаечный ключ и теперь он помогает им в работе. Известны случаи когда из конструктора С++ собирали действующее огнестрельное оружие. Двое случайно застрелились сами, остальных забрали в милицию.
В набор С++ входят три десятка основных деталей, множество веревочек, бумага, клей и маникюрные ножницы. Когда надо, вы можете самостоятельно собрать нужную деталь.
Те кто начинал с конструктора Паскаль, продолжают строить тяжелые надежные конструкции. Новички строят невообразимо уродливые сооружения, которые легче поломать чем починить. И наконец, только те кто увлекается С++ достаточно долгое время, способны построить ажурную конструкцию весом в полторы тонны, с одной точкой опоры и изменяющимся центром тяжести — благодаря умению использовать веревки.
С++ это основной язык для суровых бородатых конструкторов, однако те кто был неоднократно придавлен развалившейся поделкой, недолюбливают его.

С#
С# это один из конструкторов известной фирмы, производящей детскую не очень качественную продукцию.
Можно купить полный набор, в который будут входить множество конструкторов, иногда даже совместимых между собой.
Обычно облегченный набор конструктора С# бесплатно раздается в институтах.
Яркая коробка, веселые лица изображенные на ней, надписи вроде «Конструировать это здорово!» сделают этот конструктор хорошим подарком юному инженеру.
Внутри лежит яркая книжица, которая описывает примерно треть деталей. Остальные описываются только по платной подписке.
Детали представляют собой деревянные кубики, на которых написаны слова. Некоторые кубики пустые, на них можно написать самому все что хочешь. Изредка попадаются параллелепипеды. А еще есть одна пирамидка с надписью main, которая должна венчать самую верхнюю точку творения, иначе все развалится.
Все кубики сделаны довольно качественно, одинаковые разложены по отдельным коробочкам.
Иногда кубики с разъемами — не для дополнительной прочности, а чтобы нельзя было собрать неподходящие. Или можно, но ненадежно. Однако несмотря на одинаковые разъемы, кубики часто не собираются друг с другом.
Создатели конструктора решили ввести множество нововведений в процесс конструирования. Например запатентованная Технология Гибких Кубиков ©, запатентованная Технология Полупрозрачных Кубиков ©, запатентованная Технология Вязких Кубиков © и запатентованная Технология Липких Кубиков ©.
Решив не отказываться от веревочек, их оставили в наборе. Две. Одна обычно сделана из закаленной проволоки, поэтому не гнется, а вторая слишком короткая.
Те кто начинал свою конструкторскую деятельность с Паскаля, могут даже не заметить различий между С++ и С#.
Если человек долго работал с кубиками С#, и может, например, собрать башенку, его лицензируют как Специалиста По Кубикам.
В целом, прочность конструкции из деталей-кубиков примерно такая же как и из железных деталей, а красивая коробочка окончательно убедит большинство выбросить старый Паскаль.

HTML
HTML это даже не конструктор, это скорее мозаика. Детали — кусочки бумаги. Все они, кроме пары штук, квадратные и различаются только цветом. В качестве деталей также можно использовать камушки, стеклышки, кусочки зеркал и обрывки тряпочек. Продаются красивыми коробки с мозаикой и хвалебными рекомендациями от лучших дизайнеров, там даже есть примеры картинок которые можно собрать из существующих кусочков.
Огромное количество руководств и липовых «профессионалов мозаики» дают советы как мозаику превратить в пазл.
В мозаике почти нет методик — можно собирать хоть сверху, хоть снизу, хоть по диагонали, как больше нравится.
В неопытных руках мозаика ужасна. Вместо красивой картинки почти всегда получается вырвиглазная абстракция.
Кто то выкладывает детали на краешке стола, кто то на полу, некоторые скрепляют все цементом.
В мозаике особенно важна не прочность творения, а красота получившейся картинки.
Многие новички делают ужасные вещи — вместо того чтобы перекладывать мозаику, они накладывают детали других цветов поверх старых. Издалека незаметно, профессионалы мозаики негодуют.
Из-за кажущейся легкости, мозаику очень любят тысячи человек. Кто то собирает картинки для отдыха, кто то зарабатывает этим деньги.
С мозаикой обычно поставляются дополнительные понятия, такие как
— CSS — это когда после сборки мозаики ты перерисовываешь стиль рисунка на бумажку от руки, чтобы было легче собирать в следующий раз.
— java-script — в большинстве случаев представляет непонятно зачем приклеенный сверху к мозаике калькулятор. Некоторые любят чтобы сверху готовый шедевр был усыпан перьями или снегом. Особо раздражает когда готовую картинку заслоняют наполовину содранные объявления о продаже детской коляски и указатели на другие мозаики.
Мозаика больше подходит для художников, чем для инженеров. Художники любят ее за красоту, инженеры не любят за плоскость конструкций.

Ассемблер
Конструктор Ассемблер нужно дарить только невероятно усидчивым или нелюбимым детям.
Для Ассемблера обязательно нужны пинцет и 10-кратное увеличительное стекло.
Будьте осторожны! Конструктор Ассемблер категорически не рекомендуется в качестве первого в жизни конструктора, потому что развивает очень мелкую моторику и прямолинейное мышление.
В минимальный набор входят 79 различных деталей. Структура сборки напоминает домино — плоская и больше двух деталей за один раз не соединяются.
Обычно в процессе сборки сам забываешь что ты хотел собрать.
Собранные на Ассемблере поделки работают всегда. Правда, не всегда понятно, что именно они делают и зачем они это делают.
Зато созданные конструкции могут перестраивать сами себя в процессе работы. Но надо быть осторожным — иногда поделка внезапно начинает активно изменять законы физики окружающего мира, и становится опасной для окружающих. Тогда ее следует немедленно уничтожить.
Конструктором Ассемблер можно подковать блоху. Никакой практической пользы это не принесет, зато можно хвастаться перед друзьями.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] «Boost.Asio C++ Network Programming». Глава 1: Приступая к работе с Boost.Asio

Привет Хабралюди!
Это мой первый пост, поэтому не судите строго. Я хочу начать вольный перевод книги John Torjo «Boost.Asio C++ Network Programming» вот ссылка на нее.

Содержание:
  • Глава 1: Приступая к работе с Boost.Asio
  • Глава 2: Основы Boost.Asio
  • Глава 3: Echo Сервер/Клиент
  • Глава 4: Клиент и Сервер
  • Глава 5: Синхронное против асинхронного
  • Глава 6: Boost.Asio – другие особенности
  • Глава 7: Boost.Asio – дополнительные темы


Во-первых разберем что есть Boost.Asio, как его собрать, а так же несколько примеров. Вы узнаете, что Boost.Asio больше, чем сетевая библиотека. Так же вы узнаете о самом важном классе, который находится в самом сердце Boost.Asio —
io_service
.

Что такое Boost.Asio?

Если коротко, Boost.Asio это, большей частью, кросс-платформенная С++ библиотека для программирования сетей и некоторых других низкоуровневых программ ввода/вывода.
Есть много реализаций для решения сетевых задач, но Boost.Asio превзошел их все; он был принят в Boost в 2005 и с тех пор был протестирован большим количеством пользователей Boost, используется во многих проектах, таких как:
  • Remobo , позволяет вам создавать собственную IPN
  • libtorrent , является библиотекой, которая реализует Bittorrent клиент
  • PokerTH , представляет собой игру в покер с поддержкой LAN и Internet
Boost.Asio успешно абстрагирует понятия input и output, которые работают не только для работы в сети, но и для последовательных COM-портов, файлов и так далее. Кроме этого вы можете делать input или output программирование синхронным или асинхронным:

<code class="cpp">read(stream, buffer [, extra options]) 
async_read(stream, buffer [, extra options], handler)
write(stream, buffer [, extra options])
async_write(stream, buffer [, extra options], handler)
</code>
Как вы успели заметить в предыдущем фрагменте кода функции принимают экземпляр потока, которым может быть что угодно (не только сокет, мы можем читать и писать в него).
Библиотека является переносимой, работает на большинстве операционных систем и хорошо масштабируется при более чем тысяче одновременных подключений. Сетевая часть была последователем BSD(Berkeley Software Distribution) сокетов. Предоставляется API для работы с TCP (Transmission Control Protocol) сокетами, UDP (User Datagram Protocol) сокетами, IMCP(Internet Control Message Protocol) сокетами, так же библиотека является расширяемой, так, если вы хотите, то можете адаптировать ее на свой собственный протокол.

История

Boost.Asio была принята в Boost 1.35 в декабре 2005г, после начала разработки в 2003г. Первоначально автором является Кристофер Кохлхофф (Christopher M. Kohlhoff), с ним можно связаться по адресу chris@kohlhoff.com.
Библиотека была протестирована на следующих платформах и компиляторах:
  • 32-bit и 64-bit Windows, используя Visual C++ 7.1 и выше
  • Windows, с использованием MinGW
  • Windows, используя Cygwin (убедитесь, что определен
    __USE_232_SOCKETS
    )
  • Linux на основе ядер 2.4 и 2.6, используя g++ 3.3 и выше
  • Solaris, используя g++ 3.3 и выше
  • MAC OS X 10.4+, используя g++ 3.3 и выше
Это также может работать на платформах, таких как AIX 5.3, HP-UX 11i v3, QNX Neutrino 6.3, Solaris, с использованием Sun Studio 11+, True64 v5.1, Windows, с использованием Borland C++ 5.9.2+ (проконсультируйтесь на www.boost.org для уточнения деталей).

Зависимости

Boost.Asio зависит от следующих библиотек:
  • Boost.System: эта библиотека предоставляет поддержку операционной системе для библиотеки Boost (http://www.boost.org/doc/libs/1_51_0/doc/html/boost_system/index.html)
  • Boost.Regex: эта библиотека (опция) используется в случае, если вы используете
    read_until()
    или
    async_read_until()
    , которые принимают
    boost::regex
    параметр
  • Boost.DateTime: эта библиотека (опция) используется, если вы используете таймеры Boost.Asio
  • OpenSSL: эта библиотека (опция) используется, если вы решите использовать SSL поддержку, предоставляемую Boost.Asio

Сборка Boost.Asio

Boost.Asio это чисто заголовочная библиотека. Однако, в зависимости от компилятора и размера вашей программы, вы можете выбрать создание Boost.Asio как исходного файла. Вы можете сделать это для уменьшения времени компиляции. Это может быть сделано следующими способами:
  • Только в одном из ваших файлов, используя
    #include <boost/asio/impl/src.hpp>
    (если вы используете SSL, то
    #include <boost/asio/ssl/impl/src.hpp>
    )
  • Используя
    #define BOOST_ASIO_SEPARATE_COMPILATION
    во всех ваших исходных файлах
Заметьте, что Boost.Asio зависит от Boost.System и необязательно от Boost.Regex, так что вам нужно, по крайней мере, построить библиотеку boost, используя следующий код:

<code class="bash">bjam –with-system –with-regex stage
</code>
Если вы так же хотите построить тесты, то вы должны использовать следующий код:

<code class="bash">bjam –with-system –with-thread –with-date_time –with-regex –withserialization stage
</code>
Библиотека поставляется с большим количеством примеров, которые вы можете проверить, наряду с примерами, которые приводятся в этой книге.

Важные макросы

Используйте
BOOST_ASIO_DISABLE_THREADS
, если установлено; он отключает поддержку потоков в Boost.Asio, независимо от того был ли Boost скомпилирован с поддержкой потоков.

Синхронный против асинхронного

Во-первых, асинхронное программирование чрезвычайно отличается от синхронного программирования. В синхронном программировании все операции вы делаете в последовательном порядке, такие как чтение (запрос) из сокета S, а затем написать (ответ) в сокет. Каждая из операций является блокирующей. Так как операции блокирующие, то чтобы не прерывать основную программу, в то время как вы читаете или записываете в сокет, вы обычно создаете один или несколько потоков, которые имеют дело с сокетами ввода/вывода. Таким образом, синхронные сервер/клиенты, как правило, многопоточны.
С другой стороны, асинхронные программы управляются событиями. Вы начинаете операцию, но вы не знаете, когда она закончится; вы предоставляете
callback 
функцию, которая будет вызываться API с результатом операции, когда операция завершится. Для программистов, которые имеют большой опыт работы с QT – кросс-платформенной библиотекой от Nokia для создания графических приложений пользовательского интерфейса, это вторая натура. Таким образом, в асинхронном программировании вам не обязательно иметь больше, чем один поток.
Вы должны решить на ранней стадии вашего проекта (желательно в начале) какой подход вы будете использовать: синхронный или асинхронный, так как переключение на полпути будет трудным и подвержено ошибкам; существенно отличается не только API, семантика вашей программы будет сильно изменена (асинхронные сети, как правило, труднее для тестирования и отладки, чем синхронные). Подумайте перед тем как захотите использовать либо блокирующие вызовы и много потоков (синхронная, как правило, проще) либо мало потоков и события (асинхронный, как правило, более сложный).
Вот простой пример асинхронного клиента:

<code class="cpp">using boost::asio;
io_service service;
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
ip::tcp::socket sock(service);
sock.connect(ep);
</code>
Во-первых, ваша программа должна иметь экземпляр
io_service
. Boost.Asio использует
io_service 
для общения с сервисом ввода/вывода операционной системы. Обычно одного экземпляра
io_service 
бывает достаточно. Далее создайте адрес и порт к которому вы хотите подключиться. Создайте сокет. Подключите сокет к вашему адресу и порту:

<code class="cpp">//Here is a simple synchronous server:using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // listen on 2001
ip::tcp::acceptor acc(service, ep);
while ( true) 
{
    socket_ptr sock(new ip::tcp::socket(service));
    acc.accept(*sock);
    boost::thread( boost::bind(client_session, sock));
}
void client_session(socket_ptr sock)
 {
    while ( true)
     {
        char data[512];
        size_t len = sock->read_some(buffer(data));
        if ( len > 0) 
        write(*sock, buffer("ok", 2));
    }
}
</code>
Опять же, ваша первая программа должна иметь, по крайней мере, хотя бы один экземпляр
io_service
. Затем вы указываете порт для прослушивания и создаете акцептор (приемник) — один объект, который принимает клиентские подключения.
В следующем цикле вы создаете фиктивный сокет и ждете подключение клиента. После того как соединение установлено, вы создаете поток, который будет заниматься этой связью.
В потоке, в функции
client_session 
вы слушаете запросы клиента, интерпретируете их и отвечаете.
Для создания простого асинхронного клиента вы будете делать что-то похожее на следующее:

<code class="cpp">using boost::asio;
io_service service;
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
ip::tcp::socket sock(service);
sock.async_connect(ep, connect_handler);
service.run();
void connect_handler(const boost::system::error_code & ec)
 {
    // here we know we connected successfully
    // if ec indicates success 
}
</code>
Ваша программа должна иметь, по крайней мере один экземпляр
io_service
. Вы указываете где подключается и создается сокет. Затем, как только установлено соединение, вы асинхронно подключаетесь к адресу и порту (это завершение обработчика), то есть вызывается
connect_handler
.
После вызова
connect_handler 
проверьте код на ошибки(
ec
), и в случае успеха вы можете асинхронно написать серверу.
Обратите внимание, что цикл
service.run()
будет выполняться до тех пор пока имеются незаконченные асинхронные операции. В предыдущем примере есть только одна такая операция, это сокет
async_connect
. После этого
service.run()
завершается.
Каждая асинхронная операция имеет завершающий обработчик, функцию, которая будет вызвана, когда операция завершится.
Следующий код это простой асинхронный сервер:

<code class="cpp">using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // listen on 2001
ip::tcp::acceptor acc(service, ep);
socket_ptr sock(new ip::tcp::socket(service));
start_accept(sock);
service.run();
void start_accept(socket_ptr sock)
 {
    acc.async_accept(*sock, boost::bind( handle_accept, sock, _1) );
}
void handle_accept(socket_ptr sock, const boost::system::error_code & err)
 {
    if ( err) return;
    // at this point, you can read/write to the socket
    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}
</code>
В предыдущем фрагменте кода, во-первых, вы создаете экземпляр
io_service
. Затем вы указываете порт, который будете прослушивать. Потом создаете акцептор – объект для приема клиентских подключений, а так же создаете фиктивный сокет и асинхронно ждете подключения клиента.
Наконец, запускаете асинхронный цикл
service.run()
. При подключении клиента вызывается
handle_accept 
(завершающий обработчик для вызова
async_accept
). Если нет ошибок, то вы можете использовать этот сокет для операций чтения/записи.
После использования сокета, вы создаете новый сокет и снова вызываете
start_accept()
, которая добавляет подобную асинхронную операцию «ждем подключения клиента», оставляя цикл
service.run()
занятым.

Исключения против кодов ошибок

Boost.Asio позволяет использовать как исключения так и коды ошибок. Все синхронные функции имеют перегрузки выбрасывающие исключения в результате ошибки или возвращает код ошибки. Если функция падает, то она выбрасывает
boost::system::system_error
ошибку.

<code class="cpp">using boost::asio;
ip::tcp::endpoint ep;
ip::tcp::socket sock(service);
sock.connect(ep); // Line 1
boost::system::error_code err;
sock.connect(ep, err); // Line 2
</code>
В предыдущем коде
sock.connect(ep)
выбрасывает исключение в случае ошибки и
sock.connect(ep, err)
вернет код ошибки.
Взгляните на следующий фрагмент кода:

<code class="cpp">Try
 {
    sock.connect(ep);
} 
catch(boost::system::system_error e) 
{
    std::cout << e.code() << std::endl;
}
</code>
Следующий участок кода похож на предыдущий:

<code class="cpp">boost::system::error_code err;
sock.connect(ep, err);
if ( err)
    std::cout << err << std::endl;
</code>
В случае, если вы используете асинхронные функции, все они возвращают код ошибки, который вы можете проверить в вашей функции обратного вызова. Асинхронные функции никогда не выкидывают исключений и не имеет никакого смысла делать это. А кто его поймает?
В ваших синхронных функциях вы можете использовать как исключения так и коды ошибок (что больше захотите), но пользуйтесь чем то одним. Их смешивание может привести к проблемам или даже падению (когда вы по ошибке забываете обработать исключение). Если ваш код является комплексным (вызываются функции чтения/записи в сокет), то вам, вероятно, предпочтительней пользоваться исключениями и выполнять функции чтения и записи в
try {} catch
блоке.

<code class="cpp">void client_session(socket_ptr sock) 
{
    Try
     {
        ...
    } 
    catch ( boost::system::system_error e) 
    {
        // handle the error 
    }
}
</code>
Если вы используете коды ошибок, то вы можете хорошо увидеть, когда соединение будет закрыто, как показано в следующем фрагменте кода:

<code class="cpp">char data[512];
boost::system::error_code error;
size_t length = sock.read_some(buffer(data), error);
if (error == error::eof)
    return; // Connection closed
</code>
Все коды ошибок Boost.Asio находятся в пространстве имен
boost::asio::error
(в случае, если вы хотите сделать полный перебор для нахождения неисправности). Так же вы можете посмотреть
boost/asio/error.hpp
для получения более подробной информации.

Потоки в Boost.Asio

Когда дело доходит до потоков в Boost.Asio, нам надо поговорить о следующем:
  • io_service
    : класс
    io_service 
    является потоко-безопасным. Несколько потоков могут вызвать
    io_service::run()
    . Чаще всего вы, вероятно, вызываете
    io_service::run()
    из одного потока, так что функция ждет пока все блокирующие асинхронные функции будут выполнены. Тем не менее вы можете вызывать
    io_service::run()
    из нескольких потоков. Это блокирует все потоки, которые будут вызывать
    io_service::run()
    . Все функции обратного вызов будут вызваны в контекстах вех потоков, которые вызвали
    io_service::run()
    ; это так же означает, что если вы вызвали
    io_service::run()
    , только в одном потоке, то все функции обратного вызова будут вызваны в контексте данного потока.
  • socket
    : классы сокетов не являются потоко-безопасными. Таким образом вам следует избегать таких ситуаций как читать из сокета в одном потоке, а писать в него в другом (это рекомендуется вообще, не говоря уже о Boost.Asio).
  • utility
    : Классы
    utility 
    обычно не имеет смысла использовать в нескольких потоках, они не потоко-безопасны. Большинство из них используются короткое время, а затем выходят из области видимости.
Библиотека Boost.Asio сама по себе может использовать несколько потоков кроме вашего, но гарантируется, что из этих потоков не будет вызываться ваш код. Это в свою очередь означает, что функции обратного вызова будут вызваны только в тех потоках, откуда вызвана
io_service::run()
.

Не только сети

Boost.Asio в дополнение к сетям предоставляет и другие объекты ввода/вывода.
Boost.Asio позволяет использовать такие сигналы как
SIGTERM
(завершить программу),
SIGINT
(прерывание сигнала), SIGSEGV (нарушение сегмента) и другие.
Вы создаете экземпляр
signal_set
и указываете какие сигналы ждать асинхронно и когда один из них случится, то вызовется ваш асинхронный обработчик:

<code class="cpp">void signal_handler(const boost::system::error_code & err, int signal) 
{
    // log this, and terminate application
}
boost::asio::signal_set sig(service, SIGINT, SIGTERM);
sig.async_wait(signal_handler);
</code>
Если сгенерируется
SIGINT
, то вы попадете в обработчик
signal_handler
.
Используя Boost.Asio, вы можете легко подключиться к последовательному порту. Имя порта COM7 на Windows или /dev/ttyS0 на POSIX платформах:

<code class="cpp">io_service service;
serial_port sp(service, "COM7");
</code>
После открытия вы можете установить некоторые параметры, такие как скорость передачи данных порта, четность, стоп-биты, как указано в следующем фрагменте кода:

<code class="cpp">serial_port::baud_rate rate(9600);
sp.set_option(rate);
</code>
Если порт открыт, то вы можете обрабатывать его в потоке, к тому же рекомендуется использовать свободные функции для чтения и/или записи в последовательный порт, например,
read()
,
async_read()
,
write()
,
async_write()
, как показано в следующем примере:

<code class="cpp">char data[512];
read(sp, buffer(data, 512));
</code>
Boost.Asio позволяет также подключаться к Windows-файлам и опять же использовать свободные функции, такие как
read()
,
asyn_read()
и другие, как показано ниже:

<code class="cpp">HANDLE h = ::OpenFile(...);
windows::stream_handle sh(service, h);
char data[512];
read(h, buffer(data, 512));
</code>
Тоже самое вы можете сделать и с дескрипторами POSIX файлов, таких как пайпы, стандартные I/O, различными устройствами (но не с обычными файлами), как это сделано в следующем фрагменте:

<code class="cpp">posix::stream_descriptor sd_in(service, ::dup(STDIN_FILENO));
char data[512];
read(sd_in, buffer(data, 512));
</code>

Таймеры

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

<code class="cpp">bool read = false;
void deadline_handler(const boost::system::error_code &) 
{
    std::cout << (read ? "read successfully" : "read failed") << std::endl;
}
void read_handler(const boost::system::error_code &) 
{
    read = true;
}
ip::tcp::socket sock(service);
…
read = false;
char data[512];
sock.async_read_some(buffer(data, 512));
deadline_timer t(service, boost::posix_time::milliseconds(100));
t.async_wait(&deadline_handler);
service.run();
</code>
В предыдущем фрагменте кода если мы читаем наши данные до окончания времени,
read 
установлено в
true
, то наш партнер достучался до нас вовремя. В противном случае, когда вызывается
deadline_handler
,
read 
по-прежнему установлен в
false
, что означает, что мы не связались до конца отведенного времени.
Boost.Asio позволяет использовать синхронные таймеры, но, обычно, они эквивалентны простой операции
sleep
. Строчка
boost::this_thread::sleep(500);
и следующий фрагмент сделают тоже самое:

<code class="cpp">deadline_timer t(service, boost::posix_time::milliseconds(500));
t.wait();
</code>

Класс
io_service

Вы уже видели, что большая часть кода, которая использует Boost.Asio будет использовать некоторый экземпляр
io_service
.
io_service 
– самый важный класс в библиотеке, он имеет дело с операционной системой, ждет конца всех асинхронных операций, а потом при завершении вызывает обработчик для каждой такой операции.
Если вы решили создать ваше приложение синхронным, то вам не нужно беспокоиться о том, что я собираюсь показать в этом разделе.
Вы можете использовать экземпляр
io_service 
несколькими способами. В следующих примерах мы имеем три асинхронных операции, два соединенных сокета и таймер ожидания:
  • Один поток с одним экземпляром
    io_service 
    и одним обработчиком:

    <code class="cpp">io_service service_;
    // all the socket operations are handled by service_
    ip::tcp::socket sock1(service_);
    // all the socket operations are handled by service_
    ip::tcp::socket sock2(service_);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_, boost::posix_time::seconds(5));
    t.async_wait(timeout_handler);
    service_.run();
    </code>
  • Много потоков с одним экземпляром
    io_service 
    и несколькими обработчиками:

    <code class="cpp">io_service service_;
    ip::tcp::socket sock1(service_);
    ip::tcp::socket sock2(service_);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_, boost::posix_time::seconds(5));
    t.async_wait(timeout_handler);
    for ( int i = 0; i < 5; ++i)
        boost::thread( run_service);
    void run_service() 
    {
        service_.run();
    }
    
    </code>
  • Много потоков с несколькими экземплярами
    io_service 
    и несколькими обработчиками:

    <code class="cpp">io_service service_[2];
    ip::tcp::socket sock1(service_[0]);
    ip::tcp::socket sock2(service_[1]);
    sock1.async_connect( ep, connect_handler);
    sock2.async_connect( ep, connect_handler);
    deadline_timer t(service_[0], boost::posix_time::seconds(5));
    t.async_wait(timeout_handler); 
    for ( int i = 0; i < 2; ++i)
        boost::thread( boost::bind(run_service, i));
    
    void run_service(int idx) 
    {
        service_[idx].run();
    }
    </code>
Прежде всего обратите внимание на то, что вы не можете иметь несколько экземпляров
io_service 
в одном потоке. Не имеет смысла писать следующий код:

<code class="cpp">for ( int i = 0; i < 2; ++i) 
    service_[i].run();
</code>
Предыдущий участок кода не имеет никакого смысла, потому что
service_[1].run()
потребует
service_[0].run()
при закрытии первого. Так что все асинхронные операции
service_[1]
должны будут ждать обработки, а это не очень хорошая идея.
Во всех трех предыдущих примерах мы ждали три асинхронные операции для завершения. Чтобы объяснить различия, мы будем считать, что, спустя некоторое время, завершится операция 1 и сразу после этого завершится операция 2. Так же мы предположим, что каждому обработчику потребуется секунда, чтобы завершиться.
В первом случае мы ждем завершения всех трех операций в одном потоке. После завершения первой операции мы вызываем ее обработчик. Даже если операция 2 завершается сразу же после первой, мы будем вынуждены ждать секунду для вызова ее обработчика после завершения первой операции.
Во втором случае мы ждем завершения трех операций в двух потоках. После завершения первой операции мы вызываем ее обработчик в первом потоке. Как только завершиться операция 2, мы сразу же вызовем ее обработчик во втором потоке (в то время как первый поток занят, ожидая завершения обработчика первой операции, второй поток может свободно ответить на завершение любой другой операции).
В последнем случае, если операция 1 будет
connect 
к
sock1 
и операция 2
connect 
к
sock2
, то приложение будет вести себя как и во втором случае. Первый поток будет обрабатывать обработчик
connect 
для
sock1
, а второй поток – обработчик
connect 
для
sock2
. Однако, если из
sock1 
является операцией 1 и тайм-аут
deadline_timer t
это операция 2, то первый поток будет обрабатывать обработчик для
connect 
из
sock1
. Таким образом, обработчику тайм-аута
deadline_timer t
придется ждать конца работы обработчика
connect 
из
sock1 
(он будет ждать одну секунду), в первом потоке обрабатывается как подключение к обработчику
sock1
, так и обработчик тайм-аута
t
.
Вот что вы должны извлечь из предыдущих примеров:
  • Ситуация 1 для базовых приложений. Вы всегда будете сталкиваться с проблемами, если несколько обработчиков должны быть вызваны одновременно или же если они должны будут вызываться последовательно. Если один обработчик требует много времени для окончания, то остальным обработчикам придется подождать.
  • Ситуация 2 для большинства случаев. Это очень хорошо, если несколько обработчиков должны быть вызваны одновременно и каждый из них вызывается в отдельном потоке. Единственное узкое место может возникнуть, если все обрабатывающие потоки заняты и в то же время должны быть вызваны новые обработчики. Тем не менее, в качестве простого решения можно просто увеличить количество потоков-обработчиков.
  • Ситуация 3 является наиболее сложной и более гибкой. Вы должны ее использовать только тогда, когда ситуации 2 недостаточно. Это вероятно будет возможно, когда у вас имеется более тысячи одновременных подключений (сокетов). Вы можете считать, что каждый поток-обработчик (поток, запустивший
    io_service::run()
    ) имеет свой собственный цикл
    select/epoll
    ; он ждет все сокеты, контролирует операции чтения/записи и найдя хотя бы одну такую операцию начинает обрабатывать ее. В большинстве случаев вам не о чем беспокоиться, беспокоиться можно только в том случае, когда количество сокетов растет экспоненциально (более 1000 сокетов). В таком случае наличие нескольких циклов
    select/epoll
    может увеличить время отклика.
Если вы думаете, что ваше приложение когда-нибудь перейдет к ситуации 3, то убедитесь, что участок кода (код, который вызывает
io_service::run()
) изолирован от остального кода, чтобы его можно было легко изменять.
И наконец всегда помните, что
.run()
всегда будет закончен, если больше нет операций для контроля, как показано в примере ниже:

<code class="cpp">io_service service_;
tcp::socket sock(service_);
sock.async_connect( ep, connect_handler);
service_.run();
</code>
В этом случае как только сокет установил соединение будет вызван
connect_handler 
и
service.run()
завершится.
Если вы хотите, чтобы
service.run()
продолжил работать, вы должны предоставить ему больше работы. Есть два способа решения данной проблемы. Одним из способов является увеличение нагрузки на
connect_handler
, запустив еще одну асинхронную операцию.
Второй способ заключается в имитации некоторой его работы, используя следующий код:

<code class="cpp">typedef boost::shared_ptr<io_service::work> work_ptr;
work_ptr dummy_work(new io_service::work(service_));
</code>
Приведенный выше код обеспечит постоянную работу
service_.run()
до тех пор пока вы не вызовете
useservice_.stop()
или
dummy_work.reset(0); // destroy dummy_work
.

Резюме.

Boost.Asio является сложной библиотекой, которая делает программирование сетей довольно простым. Собрать ее просто. Она работает достаточно хорошо, избегая использования макросов; предоставляется несколько макросов для включения опций вкл/выкл, но есть несколько вещей, о которых нельзя забывать.
Boost.Asio поддерживает как синхронное так и асинхронное программирование. Эти два подхода очень разные и вы должны выбрать какой-то один и как можно раньше, так как переключение является довольно сложным и подвержено ошибкам.
Если вы выбрали синхронный подход, то вы можете выбирать между исключениями и кодами ошибок, переход от исключений к кодам ошибок довольно прост, надо добавить еще один аргумент в вызов функции (код ошибки).
Boost.Asio служит не только для программирования сетей. У этой библиотеки есть несколько особенностей, которые делают ее более ценной, такие как сигналы, таймеры и так далее.
В следующей главе мы будем вникать в множество функций и классов Boost.Asio, предусматривающие сети. Кроме того мы узнаем несколько трюков об асинхронном программировании.

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

Всем удачи!


Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Как подключиться к Hyperboria

Введение

На Хабре уже есть несколько статей про сеть Hyperboria:
Hyperboria: Интернет 2.0
Hyperboria: Как все устроено
Hyperboria: Маршрутизация

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

Здесь же я хочу написать что-то типа FAQ + гайд по подключению.

FAQ

В. О чём вообще речь?
О. О распределённой децентрализованной p2p-сети, строящейся на основе cjdns

В. И зачем оно нужно?
О. Затем, что нынешний Интернет слишком зависимый. Зависит от провайдеров и от регулирующих их государств. Подключение к mesh-сети абсолютно открыто и бесплатно, информация не может быть зацензурированна, а сопоставить ваш ipv6-адрес в сети с реальным физическим адресом невозможно (в случае полноценной mesh-сети).

В. Что нужно для подключения?
О. Девайс с *nix-системой (в т.ч., OS X)

В. А как же Windows?
О. Разработка идёт

В. А доступ в Интернет нужен?
О. Пока что – нужен, но в стратегическом плане переход на полноценную mesh-сеть.

В. Что такое mesh-сеть?
О. Cjdns поддерживает два режима работы:
  • оверлейный режим – когда связь между нодами происходит поверх обычного интернет-соединение
  • Mesh-режим – когда ноды соединяются напрямую (например, по wi-fi два недалеко стоящих роутера), без подключения к Интернет

Подключение

Сборка из исходников
Это официально предлагаемый автором метод установки (перевод мой).
Вот ещё есть README на русском от shifttstas

Вам потребуется git, cmake и всякие прочие стандартные штуки.
Для \Ubuntu:
<code class="bash">sudo apt-get install cmake git build-essential</code>
Дальше, выкачиваем себе репозиторий с github и переключаемся в соответствующую директорию:
<code class="bash">git clone https://github.com/cjdelisle/cjdns.git cjdns
cd cjdns</code>
Собственно, сборка:
<code class="bash">./do</code>
При успешной сборке в итоге вы увидите
<code class="bash">Build completed successfully</code>
Есть инструкции по установке для ArchLinux и для Gentoo

Настройка
0. Проверьте, что есть всё необходимое
<code class="bash">cat /dev/net/tun</code>
Если получится такое:
<code class="bash">cat: /dev/net/tun: File descriptor in bad state</code>
значит, всё ок! Идём дальше

Если же получили такой ответ
<code class="bash">cat: /dev/net/tun: No such file or directory</code>
выполните следующие команды:
<code class="bash">sudo mkdir /dev/net &&
sudo mknod /dev/net/tun c 10 200 &&
sudo chmod 0666 /dev/net/tun</code>
Попробуйте снова выполнить
<code class="bash">cat /dev/net/tun</code>
Если в ответ получите такое
<code class="bash">cat: /dev/net/tun: Permission denied</code>
Вы, вероятно, используете VPS на основе платформы OpenVZ. Попросите хостера включить вам «туннельный интерфейс» TUN/TAP – это стандартная штука, они должны знать, как это сделать.

1. Создайте конфигурационный файл
<code class="bash">./cjdroute --genconf >> cjdroute.conf</code>
Этот файл – ваше всё! Там ваши ключи, ipv6-адрес, пароли доступа и т.д. и т.п., соответственно, он должен быть хорошо защищён.

Установите права доступа к фалу только для себя и поместите его, например, в home
<code class="bash">chmod 600 cjdroute.conf
mv cjdroute.conf ~/.cjdroute.conf</code>
2. Найдите пиры
Самый сложный шаг – пока сеть, в основном, работает в оверлейном режиме (т.е., поверх интернет-соединения), для подключения к Hyperboria вам нужно найти кого-то, кто уже подключён.

Можно посмотреть на карте проекта, попросить в IRC-чатике irc://irc.efnet.org/#cjdns, попробовать спросить на русскоязычном форуме.

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

3. Добавьте инфу пира в конфиг
Для подключения к пиру вам потребуется его ip и порт, пароль и публичный ключ. Обычно, всё это передаётся в виде JSON, выглядит примерно так:
<code class="javascript">"123.45.67.123:34567": {
    "password": "sjfhgwetuyfdgwudbjwedgu34",
    "publicKey": "amnfbwjhfbu4bwhcbuwyrho2iudh384rgiwyebuwygriwebdfgueyr.k"
}</code>
Подобную информацию надо вставить в конфиг в поле 'connectTo'
<code class="javascript">// Nodes to connect to.
"connectTo":
{
    "0.1.2.3:45678":
    {
        "password": "thisIsNotARealConnection",
        "publicKey": "thisIsJustForAnExampleDoNotUseThisInYourConfFile.k"
    }
}</code>
Либо воспользоваться моим веб-интерфейсом (про него чуть дальше).

Можно добавлять сколько угодно пиров (и чем больше – тем лучше).

Если вы хотите предоставить кому-то доступ через вашу ноду, то данные есть в конфиге в комментарии рядом с секцией 'authorizedPasswords'.
Нужно только вписать свой внешний ip-адрес.
В секции 'authorizedPasswords' можно добавлять различные пароли для разных людей, а в json-информацию о пирах в 'connectTo' можно добавлять любые поля (например, информацию о географическом местоположении ноды).

4. Проверьте открытые порты!
После подключения к сети ваша нода получит белый статический ipv6-адрес (впрочем, доступный только из Hyperboria), поэтому важно проверить, нет ли неизвестных вам открытых портов, к которым мог бы кто-то подключиться.

5. Поехали!
<code class="bash">sudo ./cjdroute < ~/.cjdroute.conf</code>
Если нужно записывать логи:
<code class="bash">sudo ./cjdroute < ~/.cjdroute.conf > cjdroute.log</code>
Также, логи можно смотреть «в прямом эфире» через мою веб-админку

Чтобы выключить cjdns
<code class="bash">sudo killall cjdroute</code>
Для запуска cjdns не от рута тоже есть инструкция

Вы в сети
Попробуйте зайти на какой-нибудь Hyperboria-сервис.
Например, аналог Твиттера: http://socialno.de
При первом старте может потребоваться несколько минут на построение маршрутов.

Веб-интерфейс к админскому API cjdns
Я написал небольшую админку на nodejs, которую вмерджили в основной репозиторий cjdns.
Для использования вам потребуется node.js и json-файлик '~/.cjdnsadmin' со следующим содержимым:
<code class="javascript">{"config":"~/.cjdroute.conf"}</code>
Заходим в директорию репозитория cjdns, дальше переходим в директорию админки:
<code class="bash">cd contrib/nodejs/admin</code>
Устанавливаем node.js-зависимости с помощью npm:
<code class="bash">npm install</code>
Запускаем админку:
<code class="bash">node admin.js</code>
По-умолчанию, админка запускается на http://localhost:8084, никак не закрыта для доступа извне, так что не держите её запущенной постоянно.

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

Подключение в mesh-режиме
Данный тип подключения пока что работает только для linux и не работает в OS X
В идеальном случае, всё просто: надо найти в конфиге закомментированную секцию 'ETHInterface' и раскомментировать её.
Также, надо указать в поле 'bind' имя сетевого интерфейса, который вы хотите использовать для поиска нод (например, 'eth0').

Перезапустите cjdroute и если в вашей сети (физической) будут другие cjdns-ноды с включённым 'ETHInterface' – они друг к другу автоматически подключатся.

При этом, если ни одна из нод не подключена к пирам из Hyperboria, то вы получите собственную cjdns-локалку, с по-умолчанию шифрованным траффиком и прочими радостями.

Сборка OpenWRT с поддержкой cjdns

Если вы хотите установить cjdns на роутер, придётся повозиться немного дольше.

Раз вы об этом задумались, скорее всего, вам не составит труда прочитать инструкцию на английском.
Основной косяк, который допустил я сам при первой попытке – это попытка собирать OpenWRT прямо на роутере :)
Конечно, это надо делать на нормальном компе, а потом уже скомпилированную прошивку устанавливать на роутер.

Предварительно, проверьте свой роутер на совместимость.

К слову, на моём Netgear WNDR3600 оно завелось, но через неделю роутер стал жутко тупить (даже при выключенном cjdns), пришлось снести OpenWRT и поставить обратно dd-wrt.

Захват мира

Глобальные планы автора cjdns и сообщества вообще – замена нынешней сети Интернет на Hyperboria.
Сейчас есть несколько mesh-участков сети в Штатах (самый большой, если не ошибаюсь, в Сиэтле).

Предлагаю заинтересованным в построении сети в России (и в Москве, в частности) приходить на форум для разработки плана захвата.

Что уже есть в сети
Список известных сайтов

Сайты о проекте
http://hyperboria.net
http://projectmeshnet.org/
Вики проекта
Русскоязычный сайт и форум

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Расчет площади пересечения окружностей методом Монте-Карло

Monte-CarloЭта статья родилась как логическое продолжение пятничного поста о методе Бутстрапа, а особенно, комментариев к нему. Не защищая метод Бутстрапа, стоит уделить внимание методам Монте-Карло. Здесь я хочу поделиться своим опытом применения Монте-Карло в одной из своих практических задач, а также обоснованием законности этого применения.

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


Обоснование

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

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

Здесь на сцену выходит метод Монте-Карло. Благодаря современным компьютерным мощностям этот метод позволяет провести большое количество статистических испытаний, на основе результатов которых делается обобщение.

Итак, алгоритм расчета площади любой фигуры методом Монте-Карло сводится к следующему:
  1. Фигура вписывается в прямоугольник. Координаты сторон прямоугольника известны, значит, известна его площадь.
  2. Псевдослучайным образом внутри прямоугольника генерируется большое количество точек. Для каждой точки определяется, попала ли точка внутрь исходной фигуры или нет.
  3. В результате площадь исходной фигуры вычисляется исходя из обычной пропорции: отношение количества точек, попавших в фигуру, к общему количеству сгенерированных точек равно отношению площади фигуры к площади ограничивающего ее прямоугольника.
Последняя проблема, которую надо решить, заключается в том, что каким-то образом необходимо определять, попала ли точка внутрь исходной фигуры. В моем случае данная задача решается достаточно просто, поскольку моя фигура состоит из окружностей, координаты центров и радиусы которых известны.

Реализация задачи на JavaScript

Рисование окружностей делалось средствами замечательной библиотеки D3.js. Алгоритм начального взаимного расположения окружностей выходит за рамки данной статьи, поэтому примем начальное расположение как данность.
Собираем массив пересечений пар окружностей
<code class="javascript">var nodes = d3.selectAll("circle.node");

var squares = [];
var intersections = [];

nodes.each(function(node){
   // считаем радиус и площадь окружности
   var r = this.r.baseVal.value;
   var s = 3.14159*r*r;
   squares.push({node: node, square: s, r: r});

   // ищем пересечения пар окружностей
    nodes.each(function(node2){
        // расстояние между центрами и сумма радиусов
        var center_dist = Math.sqrt(Math.pow(node.x-node2.x, 2)+(Math.pow(node.y-node2.y, 2)));
        var radius_sum = r + this.r.baseVal.value;
        if(center_dist <= radius_sum && node.index != node2.index){
            // окружности пересекаются. проверить, что это пересечение найдено впервые
            node.r = r;
            node2.r = this.r.baseVal.value;
            if(isNewIntersection(intersections, node, node2)) 
                  intersections.push({node1: node, node2: node2, center_dist: center_dist});
        }
    });
});
</code>

Считаем площадь фигуры
<code class="javascript">var areaCalculator = {
  intersections: [], // массив пересечений, устанавливается снаружи
  frame: {}, // рамка вокруг фигуры
  circles: [], // массив окружностей
  figureArea: 0, // искомая площадь фигуры
  monteCarlo:
      function(p){
          // получаем массив окружностей из пересечения
          var circles = [];
          var x1_, y1_, x2_, y2_; // координаты сторон прямоугольника
          var inCirclesArr = function(node){
              for(var j=0; j<circles.length; j++){
                  if(circles[j].index==node.index){
                      return true;
                  }
              }
              return false;
          };
          for(var i=0; i<this.intersections.length; i++){
              if(!inCirclesArr(this.intersections[i].node1)){
                  circles.push(this.intersections[i].node1);
              }
              if(!inCirclesArr(this.intersections[i].node2)){
                  circles.push(this.intersections[i].node2);
              }
          }

          this.circles = circles;

          circles.sort(function(a,b){
              return a.x-a.r > b.x-b.r ? 1 : -1;
          });
          x1_ = circles[0].x-circles[0].r;

          circles.sort(function(a,b){
              return a.x+a.r < b.x+b.r ? 1 : -1;
          });
          x2_ = circles[0].x+circles[0].r;

          circles.sort(function(a,b){
              return a.y-a.r > b.y-b.r ? 1 : -1;
          });
          y1_ = circles[0].y-circles[0].r;

          circles.sort(function(a,b){
              return a.y+a.r < b.y+b.r ? 1 : -1;
          });
          y2_ = circles[0].y+circles[0].r;

          this.frame.x1 = x1_;
          this.frame.x2 = x2_;
          this.frame.y1 = y1_;
          this.frame.y2 = y2_;
          this.frame.area = (x2_-x1_)*(y2_-y1_);
          
          // рисуем прямоугольник
          paintRect(this.frame);          

          // p - количество генерируемых точек. В примере использовалось 100.000, чего хватило для приемлемой точности
          var p_positive = 0; // количество точек попавших в фигуру

          // генерируем p точек для определения площади фигуры
          for(var i=0; i<p; i++){
              var x_rand = Math.random()*(x2_-x1_)+x1_;
              var y_rand = Math.random()*(y2_-y1_)+y1_;

              var yes = false;
              for(var j=0; j<circles.length; j++) {
                  if(!yes && (
                        (circles[j].x-circles[j].r) <= x_rand &&
                        (circles[j].x+circles[j].r) >= x_rand &&
                        (circles[j].y-circles[j].r) <= y_rand &&
                        (circles[j].y+circles[j].r) >= y_rand )
                    ){
                     yes = true;
                     p_positive++;
                  }
              }
          }

          // площадь фигуры = площадь прямоугольника*кол-во точек внутри фигуры / общее кол-во точек
          this.figureArea = this.frame.area*p_positive/p;
      }
};
</code>

Результат

Пара гвоздей в метод Бутстрапа

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

Заключение

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Выполнение внешнего файла из БД Oracle с целью получения информации о дисковом пространстве

Зачастую для тех или иных нужд возникает необходимость выполнить команду OS из pl/sql или даже sql внутри Oracle Database.
Ниже описывается один из способов и его применение в задаче определения доступного дискового пространства.
Предлагаемый способ заключается в использование добавленного в 11.2 функционала «Препроцессинг данных внешних таблиц».


Таким образом нам потребуется создать объекты:
  • Directory — в ней будет располагаться наш скрипт препроцессинга и на неё будет ссылаться таблица
  • external organization table — обращение к которой будет вызывать выполнение скрипта
  • script — собственно сам файл который будет выполнять требуемое нам действие в OS

Пример создания требуемых объектов:
<code class="sql">-- directory
create or replace directory UTIL_DIR as '/u01'
/
-- table
CREATE TABLE T_OS_COMMAND  (
 v_line varchar2(4000)  )
 ORGANIZATION external
 ( TYPE oracle_loader
 DEFAULT DIRECTORY UTIL_DIR
 ACCESS PARAMETERS
 ( RECORDS DELIMITED BY NEWLINE
 preprocessor UTIL_DIR:'os_command.sh'
 FIELDS TERMINATED BY "\n" LDRTRIM
 )
 location ( 'os_command.sh')
 )
/
</code>
Лучше всего иметь отдельную directory для наших целей ввиду того что нам потребуется одновременно и права на запись в ней и права на выполнение, а такую комбинацию лучше никому не выдавать.
Оптимальное использование это создание пакета (хоть и в схеме SYS) в спецификации которого описаны процедуры, которым необходимо обращение к OS, а саму реализацию оставить внутри пакета и никого к ней не подпускать.
Далее подразумевается что права на чтение, запись и выполнение к UTIL_DIR у нас имеются, также как и права на select из T_OS_COMMAND.

Для создания файла который будет выполнятся достаточно выполнить в OS (да придется хоть раз выполнить действия в OS прибегнув к более тривиальным методам — например ssh):
<code class="bash">$touch /u01/os_command.sh
$chmod ug+x /u01/os_command.sh
</code>
Данные команды должны быть выполнены от пользователя (либо члена группы) от которых запускается экземпляр БД.

Всё готово к использованию. Для выполнения произвольной команды OS нам следует записать её в файл os_command.sh и обратиться с запросом к таблице T_OS_COMMAND.
<code class="sql">declare
  F1 UTL_FILE.FILE_TYPE;
begin
  F1 := UTL_FILE.FOPEN('UTIL_DIR','os_command.sh','W', 4048); 
  UTL_FILE.PUT_LINE (file => F1, buffer => '#!/bin/sh');
  UTL_FILE.PUT_LINE (file => F1, buffer => 'export LANG=en_US.UTF-8');
  UTL_FILE.PUT_LINE (file => F1, buffer => 'export PATH=$PATH:/bin');
  UTL_FILE.PUT_LINE (file => F1, buffer => 'df -k | grep /');
  UTL_FILE.fclose (file => F1);
end;
/
</code>
Теперь для получения результата работы нашего скрипт достаточно выполнить запрос к таблице T_OS_COMMAND
При выполнении в OS команды df -k | grep / мы получим
<code class="bash">/dev/sda2             32414672  14870956  15870548  49% /
/dev/sda1               124427     18001    100002  16% /boot
tmpfs                  8219820    184808   8035012   3% /dev/shm
/dev/sdb2            961432104 606013444 306580660  67% /u02
</code>

При выполнении запроса SELECT * FROM T_OS_COMMAND
V_LINE
/dev/sda2             32414672  14871076  15870428  49% /
/dev/sda1               124427     18001    100002  16% /boot
tmpfs                  8219820    184808   8035012   3% /dev/shm
/dev/sdb2            961432104 606013444 306580660  67% /u02

Далее можно приступать к реализации непосредственно методов которым необходим вызов команд OS.

Примером такой реализации может выступать пакет P_SYS_UTILITY. Пожелания по его развитию и участие в оном приветствуются.
Спецификация пакета
<code class="sql">create or replace package P_SYS_UTILITY is

  -- Author  : ALEXEY
  -- Created : 23.08.2013
  -- Purpose : Get system info (*nix versions)

/*
Get on file or folder name its device or ASM group and used/free space on it 
 * raw devices not supported
*/
procedure Get_Disk_Usage ( p_file_name  in varchar2, -- file name (also accept only path)
                           o_mount_dev  out nocopy varchar2, -- device or ASM group
                           o_used_space out number, -- used space
                           o_free_space out number); -- free space 

-- Collect space USAGE in BD
-- Recomended evry day schedule run
procedure Collect_Usage;

-- Get Forecast on space usage
-- Recomended base from 10 collects
function Get_Forecast ( pDT         in date, -- date for forecast
                        pBASE       in integer default 188, -- base days in calculate forecast
                        pTYPE_F     in varchar2 default 'SLOPE', -- type forecast: SLOPE | AVG
                        pTABLESPACE in varchar2 default null, -- tablespace ( null = all )
                        pOWNER      in varchar2 default null, -- user ( null = all )
                        pTYPE       in varchar2 default null )  -- segment type ( null = all ), allow like
         return number; -- size in bytes on date pDT

-- Get score of space usage and availability
-- Can be used in external monitoring tool : Nagios, etc
function Get_Space_Status ( pFOREDAYS   in number default 60,  -- days after that
                            pFREE_PRCNT in number default 25 ) -- free cpace greater than
         return number; -- 0 - Space free enough .. 100 - not enough free space

end P_SYS_UTILITY;
</code>

Метод Get_Disk_Usage

p_file_name — имя файла или папки для месторасположения которого(-ой) будет произведен расчет. Позволяет передавать имена относящиеся к ASM disk groups.
o_mount_dev — имя устройства в системе на которое смонтировано указанное месторасположение, определяется из вывода команды df. Для ASM будет возвращено имя disk group.
o_used_space — количество байт занятых на устройстве/diskgroup
o_free_space — количество байт доступных на устройстве/diskgroup
Осуществляет вызов df с передачей в качестве параметра имени файла, или обращение к v$asm_diskgroup в случае если имя файла начинается на "+".

Метод Collect_Usage
Осуществляет сбор информации об использовании пространства внутри БД. Группирует по табличным пространствам, владельцам и типам сегментов. Не берет в учет сегменты типа undo и temp. Сохраняет полученную информацию в таблицу T_SPACE_USAGE. Рекомендуется к ежедневному выполнению.
Структура T_SPACE_USAGE
<code class="sql">create table T_SPACE_USAGE (
  dt$ date,
  owner$ varchar2(30),
  tablespace$ varchar2(30),
  type$ varchar2(18),
  bytes$ number,
  blocks$ number);
create index INDX_T_SPACE_USAGE_DT on T_SPACE_USAGE (dt$);
comment on table T_SPACE_USAGE is 'Store archive data of usage space in RDBMS';
comment on column T_SPACE_USAGE.DT$ is 'Date collect space usage';
comment on column T_SPACE_USAGE.OWNER$ is 'Segment owner - user in BD';
comment on column T_SPACE_USAGE.TABLESPACE$ is 'Name of tablespace in BD';
comment on column T_SPACE_USAGE.TYPE$ is 'Segment type';
comment on column T_SPACE_USAGE.BYTES$ is 'Size in bytes';
comment on column T_SPACE_USAGE.BLOCKS$ is 'Size in blocks';
</code>


Метод Get_Forecast

pDT — дата на которую надо спрогнозировать размер
pBASE — количество дней, данные за которые войдут в базу по которой будет строиться прогноз
pTYPE_F — способ прогнозирования — либо на основе ковариация (генеральной) совокупности, либо на основе среднего изменения
pTABLESPACE — табличное пространство по которому производится прогнозирование, если не передавать то по всем
pOWNER — владелец схемы по которому производится прогнозирование, если не передавать то по всем
pTYPE — тип сегментов данных по которому производится прогнозирование, если не передавать то по всем
Выполняет расчет прогнозируемого занимаемого места сегментов согласно указанным критериям. Результат в байтах.

Метод Get_Space_Status

pFOREDAYS — количество дней для прогноза
pFREE_PRCNT — процент доступного пространства (считается от прогнозируемого занятого)
Производит оценку по шкале от 0 до 100 доступного для роста БД пространства.

Также учитывает ограничения на рост файлов внутри БД.

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

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[recovery mode] А давайте им поможем блокировки контента и сайтов

Я уже несколько недель смотрю на это сумашедствие в интернете и принимаемых Думмой законах…
Вот решил подать сообществу идею. Идея достаточно маргинальная но все же…
А давайте им поможем, для того что бы собрать народ и действительно что бы большая часть интернет пользователей осознала происходящее нужно что бы не по крохам все закрывалось а масово и сразу.

Объясню саму идею

Мы все как продвинутые пользователи интернета знаем большинство ресурсов и альтернатив где можно скачать любимые сериалы и фильмы.
Давайте все эти сразу передадим в Роснадзор, давайте подадим ссылки на интернет проекты типа Карамбы, у которой почти 20 000 000 подписчиков по разным проектам так как она попадает под «несущие зло» ресурсы, «развращает детей», This is Xorosho, EX.UA и другие, скидывать все ссылки без разбора, писать жалобы и быть Павликами Морозовыми.
Давайте скинем ссылки на электронные книги и бибилиотеки

Что бы школьники поднимали родителей что не доступных книг, а те что есть стоят денег, а те в свою очередь пересмотрев 20 сайтов увидели надпись «заблокировано» и не найдя своего любимого сериала начали хоть немного интересоватся ситуацией.

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

Я думаю будет 2 варианта

1) Люди начнут использовать VPN технологии, и с закона толку будет мало

2) Люди начнут все таки делать митинги и добиватся свободы слова, не 100 тыс человек а милионами поднимать этот вопрос.

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

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Электронные библиотеки на работе и дома

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

Работаю в западном… не, всё же северном университете, и приходится читать немало статей из своей области исследований. Благо, тут университетская библиотека подписана на множество электронных библиотек (интересно, сколько это удовольствие стоит… не, не так – сколько буржуи наживаются на наших статьях?). По моей тематике таких библиотек три – ACM, IEEE и Springer. А в них – львиная доля того, что мне нужно. И всё бы здорово, но есть одно НО.

Электронные библиотеки (ЭБ) определяют пользователей, видимо, по IP. Может я не прав, но доступ к ним открыт только если компьютер физически (через витую пару) подключен к сети Университета. По крайней мере, на станицах ЭБ значится по чьей подписке я могу скачивать статьи. Достаточно только подключиться к сети Университета по беспроводной сети, как сразу же ЭБ начинает просить деньги за статью. Понятное дело, за пределами университета я только и вижу только тарифы на чтение труда коллег и своего собственного.

А что если я дома решил поработать (ну это я шучу: кто это сможет поработать в присутствии трёх сорванцов…) ну или в командировке мне позарез понадобилось что–то проверить, уточнить, или просто почитать, в конце–концов (очень реальный случай)? В какой–то момент, я решил надо как–то это дело решать. Местный админ обрадовал меня только тем, что я не первый кто просит у него придумать решение как получить доступ к ЭБ удалённо. Без обещаний что–либо сделать. Позже от коллеги узнал что есть какое–то решение на общенациональном ресурсе, но работает оно как–то нестабильно – несмотря не то что коллега показала как она подключается к ЭБ через этот ресурс, у меня почему–то те же действия не привели к желаемому результату.

Вот тогда и появилось решение сделать всё самому, поскольку имеются небольшие навыки программирования PHP и JS. А также тот факт, что есть папки пользователей в локальной сети (из–под которой действует подписка на ЭБ), и в них можно размещать PHP–скрипты. Задумка выглядела так:
  • разместить прокси в своей папке на локальном сервере Университета,
  • написать расширение под Google Chrome, чтобы
  • все ведущие на страницах ЭБ «не туда» (не на PDF статьи) менялись бы «на лету», т.е. всё выглядело бы так как будто нет никакого прокси и статьи открываются так как будто работаешь из внутренней сети Университета.
После поиска PHP проксей был взят простенький скрипт (благодарности Eric-Sebastien Lachance) передающий все HTTP заголовки (т.е. включая куки пользователя). Правда, его пришлось весьма расширить, чтобы 1) ограничить число доменов к которым можно обращаться пользователю, и 2) разрешать пользоваться им только студентам и работникам Университета (ну вы понимаете почему это не может стать доступным для всех желающих...), а для этого проверять залогинен ли пользователь в локальной сети (Интранете, залогиниться туда можно удалённо; кстати, этот шаг можно опустить, если пользоватся только самому). Для этого в каждом запросе, кроме собственно URL на PDF статьи, должен присутствовать ID его сессии в Интранете. Прокси делает запрос на страницу Интранета, установив нужный куки (JSESSIONID в моём случае) в переданное значение, и если от Интранета приходит положительный ответ, то выполняет запрос к ЭБ.
Проверка пользователя
<code class="php">function verifyUser($authCookieValue) {
	global $authCheckURL;
	global $authSuccessHTML;
	global $authCookieName;

	$result = false;
	$error = '';
	
	// create a new cURL resource
	$ch = curl_init();
	if ($ch !== false) {
		// set URL and other appropriate options
		$header = array();
		$header[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
		$header[] = 'Accept-Language: en-US,en;q=0.5';
		$header[] = 'Connection: close';
		$header[] = 'DNT: 1';

		curl_setopt($ch, CURLOPT_URL, $authCheckURL);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0');
		curl_setopt($ch, CURLOPT_COOKIESESSION, true);
		curl_setopt($ch, CURLOPT_COOKIE, $authCookieName.'='.$authCookieValue);
		curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		// grab URL and pass it to the browser
		$response = curl_exec($ch);

		if($response === false) {
			$error = curl_error($ch);
		} else {
			$result = strpos($response, $authSuccessHTML) !== false;
		}

		curl_close($ch);
	} else {
		$error = 'cannot initialize cURL';
	}
	
	return array(
			'succeeded' => $result,
			'error' => $error
	);
}
</code>

На стороне пользователя работает расширение Google Chrome (состоит из двух частей – встраиваемый в страницу код, и код с доступом к вкладкам и куки работающий в фоновом режиме), и если URL относится к одной из трёх библиотек, то страница при загрузке сканируется на наличие определённых элементов которые должны быть на каждой странице где есть ссылка на PDF статьи (для каждой ЭБ это, конечно, разные элементы). Если такие элементы найдены, то туда подставляется запрос к прокси с правильно сформированной ссылкой на PDF статью. (Поиск того как и из каких из данных на странице правильно сформировать ссылку занял довольно немало времени).
Пример для ACM
<code class="javascript">// proxy config
var PROXY_URL = 'http://university.org/~user/proxy.php?';
var PROXY_URL_QUERY = 'urlForProxy=';
var PROXY_ID_QUERY = 'idForProxy=';

// page search and modification const
var ACM_PDF_LINK_NAME = 'FullTextPDF';
var ACM_ARTICLE_ID_NAME = 'id';
var ACM_PURCHASE_LINK = 'https://dl.acm.org/purchase.cfm';
var ACM_QUERY_URL = 'http://dl.acm.org/ft_gateway.cfm';
var ACM_QUERY = 'id={0}';
var ACM_LINK = '<a name="' + ACM_PDF_LINK_NAME + '" title="FullText PDF" href="{0}" target="_blank"><img src="imagetypes/pdf_logo.gif" alt="PDF" class="fulltext_lnk" border="0">PDF</a> [proxy]';

// requests to the background page
var REQUEST_AUTH = 'auth';

function setACMLink() {
	var pdfLink = document.getElementsByName(ACM_PDF_LINK_NAME)[0];
	if (!pdfLink) {
		var i, id, param;
		var params = window.location.search.substr(1).split('&');
		for (i = 0; i < params.length; i++) {
			param = params[i].split('=');
			if (param[0] === ACM_ARTICLE_ID_NAME) {
				id = param[1].indexOf('.') > 0 ? param[1].split('.')[1] : param[1];
				break;
			}
		}

		if (id) {
			var link = PROXY_URL + ACM_QUERY.format(id) + '&' +
				PROXY_URL_QUERY + encodeURIComponent(ACM_QUERY_URL);

			// purchase link is a placeholder for a link to PDF
			var a, container;
			var links = document.getElementsByTagName('a');
			for (i = 0; i < links.length; i++) {
				a = links[i];
				if (a.href.indexOf(ACM_PURCHASE_LINK) === 0) {
					container = a.parentNode;
					container.innerHTML = ACM_LINK.format('#');
					setClick(container.childNodes[0], link);
					break;
				}
			}
		}
	}
}

function setClick(elem, link) {
	elem.addEventListener('click', function (e) {
		commPort.postMessage({name: REQUEST_AUTH, href: link});
		e.preventDefault();
		return false;
	});
}
</code>

При клике на это ссылку к запросу присоединяется значение куки которая содержит ID сессии в Интранете Университета.
Добавление идентификатора сессии в ИнтранетеВ фоновом коде:
<code class="javascript">// config
var AUTH_URL = 'https://university.org/intranet';
var AUTH_COOKIE = 'JSESSIONID';

// const
var REQUEST_AUTH = 'auth';

chrome.runtime.onConnect.addListener(function (port) {
	port.onMessage.addListener(function (request) {
		var answer = {toRequest: request.name};
		if (request.name === REQUEST_AUTH) {	// check the authorization on the select web-site
			answer.href = request.href;
			answer.result = false;
			answer.id = '';
			chrome.cookies.get({url: AUTH_URL, name: AUTH_COOKIE}, function (cookie) {
				if (cookie) {
					answer.result = true;
					answer.id = cookie.value;
				}
				port.postMessage(answer);
			});
		} 
	});
});
</code>
Во встроеном в страницу коде:
<code class="javascript">var commPort = chrome.runtime.connect();
commPort.onMessage.addListener(function (answer) {
	if (answer.toRequest === REQUEST_AUTH) {
		// add an authorization id, and send the request to to the proxy
		window.location = answer.href + '&' + PROXY_ID_QUERY + answer.id;
	} 
});
</code>

Правда, для того чтобы открывались статьи на IEEE пришлось немало повозиться. Оказывается, для IEEE нужно открыть любую страницу на сайте его ЭБ через прокси (в Хроме открывается дополнительная вкладка, которая закрывается сразу после загрузки контента), чтобы получить от него куки с идентификаторами пользователя с подпиской. Плюс пришлось поколдовать с заменой в полученных куки значений domain и path (последнее было необязательным) в PHP, чтобы они могли автоматически передаваться вместе с запросом на PDF к прокси: приходили они (после этого дополнительного запроса для получения идентификаторов) как domain=ieeexplore.ieee.org, а линк на PDF уже указывал не на .ieeexplore.ieee.org/query, а на university.org/~user/proxy?url= ieeexplore.ieee.org%5Fquery, поэтому надо было править их на domain=.university.org, path=/~user/proxy.
Переделка куки полученых от IEEE
<code class="javascript">// config
$cookieDomain = '.university.org';
$cookiePath = '/~user';

$headerArray = explode("\r\n", $response['header']);

$js = '';
foreach ($headerArray as $headerLine) {
	if (strpos($destinationURL, 'ieee.org') !== false) {
		if (strpos($headerLine, 'Set-Cookie: ') !== false) {
			$cookieArray = explode(': ', $headerLine, 2);
			$headerLine = $cookieArray[0].': ';

			$cookieDataArray = explode('; ', $cookieArray[1]);
			$isFirstKey = true;
			$js .= '  document.cookie = "';
			foreach ($cookieDataArray as $cdKey => $cookieData) {
				list($cname, $cvalue) = array_merge(explode('=', $cookieData), array(''));
				if ($cname === 'domain') {
					$cvalue = $cookieDomain;
					$cookieDataArray[$cdKey] = $cname.'='.$cvalue;
				}
				if ($cname === 'path') {
					$cvalue = $cookiePath;
					$cookieDataArray[$cdKey] = $cname.'='.$cvalue;
				}
				$headerLine .= ($isFirstKey ? '' : '; ').$cookieDataArray[$cdKey];
				$js .= ($isFirstKey ? '' : '; ').$cookieDataArray[$cdKey];
				$isFirstKey = false;
			}
			$js .= "\";\r\n";
		}
		header($headerLine);

		if (strlen($js) > 0) {
			echo "\r\n<script>\r\n".$js.'</script>'; // insert JS code into the page to set IEEE session and identification cookies
		}
	} else {
		foreach ($headerArray as $headerLine) {
			header($headerLine);
		}
	}
}
</code>

Последнее что хочу отметить, так это то это слабые стороны такой реализации:
  • Если поменяется что–то в вёрстке страниц ЭБ, это решение перестанет работать. Зато пока работает это очень удобно: залогинился в Интранете, и работаешь
  • Есть кое–какие проблемы с безопасностью: идентификатор сессии передаётся по HTTP, и потенциально его можно перехватить. Пока я один использую это решение, риск мне видится нулевым – как злоумышленник узнает что за набор цифр я передаю в прокси? Однако если он изучит расширение, получение доступа к чужому аккаунту в Интранете Университета станет делом техники. А HTTPS на директории пользователей на нашем сервере не распространяется… Возможно, надо будет использовать шифрование идентификатора сессии в расширении (CryptoJS) и расшифровку на стороне сервера (пока не нашёл, как: буду признателен за подсказку), так как всё же планирую разослать расширение коллегам
А вот полный исходный код.

P.S. Если кто–то знает лучшее и такое же удобное решение, просьба поделиться. Можно брать код, пользовать, редактировать, делиться и т.д. Вообще, есть идея это на github залить, и если будут пожелания в комментариях, то так и сделаю.
P.P.S. За код сильно не ругайте — времени больше ушло на выяснение какие слать запросы проски (особенно для ЭБ на IEEE), чем на сам код. Он может также неполным — не всегда подставлять правилный линк.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] GWT-Platform основы работы с презентерами

Всем хабражителям доброго времени суток!

Я начинающий Java-программист и так уж получилось, что свою карьеру я начинаю с разработки серьезного приложения на GWT. На хабре довольно много статей на тему GWT, однако почему-то совсем нет информации о замечательном фреймворке GWT-Platform. Подробно познакомиться с данным фреймворком можно тут, а я расскажу вкратце об основах работы на примере простого приложения.

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

Если нажать на кнопку в навбаре, то откроется либо левая часть приложения, либо правая с бессмысленным текстом.

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






Итак, для начала нам нужно создать GWT проект в IDE. Для работы с GWTP нам потребуется добавить в проект библиотеки: guice-2.0.jar, guice-3.0.jar, gwtp-all-1.0.jar, aopalliance.jar, guice-assistedinject-3.0.jar. Также я добавил gwt-bootstrap-2.2.2.0-SNAPSHOT.jar чтобы добавить “красоты” приложению.



Можно установить в Eclipse gwt-platform плагин. Он сильно облегчает жизнь. С его помощью можно создавать как новые проекты, так и связки презентер-вью. Качается по этой ссылке: plugin.gwt-platform.googlecode.com/hg/update

Приступим:
Нужно создать клиентский модуль и Ginjector. Если приложение создавать с помощью плагина, то они будут созданы автоматически:
В методе configure () мы будем биндить наши презентеры с интерфейсами и имплементацией их вью.
<code class="java">public class ClientModule extends AbstractPresenterModule {

	@Override
	protected void configure() {
		install(new DefaultModule(ClientPlaceManager.class));

                          bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class,
				MainPageView.class, MainPagePresenter.MyProxy.class);

		bindConstant().annotatedWith(DefaultPlace.class).to(NameTokens.main);
	}
}
</code>

<code class="java">         @GinModules({ DispatchAsyncModule.class, ClientModule.class })
         public interface ClientGinjector extends Ginjector {

	EventBus getEventBus();

	PlaceManager getPlaceManager();

	Provider<MainPagePresenter> getMainPagePresenter();
}
</code>

Далее наша точка входа: Тут мы говорим нашему placemanager перейти на текущую страницу (place). То есть если у нас в адресной строке браузера был введен какой-то токен, определяющий необходимый place, то мы попадем туда. Конечно при условии что мы имеем доступ. (За это может отвечать например GateKeeper).

<code class="java">public class HabraTest implements EntryPoint {

	private final ClientGinjector ginjector = GWT.create(ClientGinjector.class);

	@Override
	public void onModuleLoad() {
		DelayedBindRegistry.bind(ginjector);	
		ginjector.getPlaceManager().revealCurrentPlace();
	}
}
</code>

Не буду заострять внимание на работе с place. На хабре уже было много замечательных статей по GWT. Например эта.

Я же покажу как можно создавать небольшие GWT приложения без использования place (точнее с одним place).

Для начала создадим главный презентер нашего приложения:

<code class="java">public class MainPagePresenter extends
	Presenter<MainPagePresenter.MyView, MainPagePresenter.MyProxy> implements MainPageUiHandlers, FirstPageEvent.Handler{

	public interface MyView extends View, HasUiHandlers<MainPageUiHandlers> {
	}
	
	// идентификаторы слотов для вставки соответствующего презентера
	public final static Object SLOT_FIRST_PAGE =  new Object();
	public final static Object SLOT_SECOND_PAGE =  new Object();
	
	//вложенные  презентеры
	private FirstPagePresenter firstPagePresenter;
	private SecondPagePresenter secondPagePresenter;	

	@ProxyStandard
	@NameToken(NameTokens.main)
	public interface MyProxy extends ProxyPlace<MainPagePresenter> {
	}

	private EventBus eventBus;
	private final PlaceManager placeManager;

	// инжектим вложенные презентеры
	@Inject
	public MainPagePresenter(final EventBus eventBus, final MyView view, 
			FirstPagePresenter firstPagePresenter,
			SecondPagePresenter secondPagePresenter,
			final MyProxy proxy, final PlaceManager placeManager) {
		super(eventBus, view, proxy);
		this.placeManager = placeManager;
		this.firstPagePresenter =  firstPagePresenter;
		this.secondPagePresenter =  secondPagePresenter;
		this.eventBus =  eventBus;
		// назначаем себя обработчиком событий  вью
		getView().setUiHandlers(this);
		eventBus.addHandler(FirstPageEvent.getType(), this);
	}

	// внедряем себя в главный презентер приложения
	@Override
	protected void revealInParent() {
		RevealRootContentEvent.fire(this, this);
	}

	@Override
	protected void onBind() {
		super.onBind();
		// по умолчанию  будет загружена первая страница
		getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter);	
	}

	// вызывается при нажатии левой кнопки в MainPageView
	@Override
	public void onRightBtnClicked() {
		showRightContent();
		MainPageEvent mainPageEvent =  new MainPageEvent( MainPageEvent.Action.SHOW_LOREM_IPSUM);
		eventBus.fireEvent(mainPageEvent);	
	}
	// аналогично при нажатии правой
	@Override
	public void onLeftBtnClicked() {
		showLeftContent();
		
	}	
	
	public void showLeftContent() {
		removeFromSlot(SLOT_SECOND_PAGE, secondPagePresenter);
		getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter);		
	}

	public void showRightContent() {
		removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter);
		getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter);	
	}

	@Override
	public void onFirstPageEvent(FirstPageEvent event) {
		// закрываем левый контент и открываем правый, в который через эвент передаем имя и фамилию
		showRightContent();
		MainPageEvent mainPageEvent =  new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(),                          event.getLastName());    
		eventBus.fireEvent(mainPageEvent);
	
	}	
}
</code>

Обратите внимание на то что мы заинжектили в конструкторе FirstPagePresenter firstPagePresenter, SecondPagePresenter secondPagePresenter.
Это будут presenter — виджеты представляющие левую и правую часть приложения (то есть в теории отдельные страницы);

В GWTP есть три основных типа презентеров:
  • Перезентеры, которые являются еще и place
  • Перезентеры-виджеты(PresenterWidget)
  • Презентеры-виджеты, представляющие собой Popup окно

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

Для смены «страниц» мы будем использовать систему слотов и презентер-виджеты помещенные в слоты.
Презентер-виджет это презентер который не обязательно является синглтоном. Он может имет множество независимых instance.
Благодаря системе слотов мы можем бесконечно вкладывать презентеры внутри других презентеров. Чтобы поместить презентер-виджет в другой презентер, нам необходимо определить слоты в родительском презентере и переопределить метод setInSlot() во вью родительского презентера.

В классе MainPagePresenter видно что слот это просто Object:

<code class="java">	public final static Object SLOT_FIRST_PAGE =  new Object();
	public final static Object SLOT_SECOND_PAGE =  new Object();
</code>

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

<code class="java">public class MainPageView extends ViewWithUiHandlers<MainPageUiHandlers> implements MainPagePresenter.MyView {

	// главная панель приложения
	@UiField HTMLPanel main;
	// навигационная панель
	@UiField ResponsiveNavbar navbar;

	// кнопки навигации
	@UiField Button firstPageBtn, secondPageBtn;
		
	private static MainPageViewUiBinder uiBinder = GWT
			.create(MainPageViewUiBinder.class);

	interface MainPageViewUiBinder extends UiBinder<Widget, MainPageView> {
	}

	// колонки для вставки контента 
	@UiField Column leftColumn, rightColumn;

	@Inject
	public MainPageView() {	
		uiBinder.createAndBindUi(this);
		navbar.setInverse(true);
		//обработчики для кнопок 
		firstPageBtn.addClickHandler(new  ClickHandler() {		
			@Override
			public void onClick(ClickEvent event) {
				getUiHandlers().onLeftBtnClicked();		
			}
		});
		
		secondPageBtn.addClickHandler(new  ClickHandler() {		
			@Override
			public void onClick(ClickEvent event) {
				getUiHandlers().onRightBtnClicked();		
			}
		});			
	}

	@Override
	public Widget asWidget() {
		return main;
	}
	
	// переопределяем метод вставки презентеров в слот
	@Override
	public void setInSlot(Object slot, IsWidget content) {
		if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) {
			leftColumn.add(content);
		}
		else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){
			rightColumn.add(content);
		}
		else {
			super.setInSlot(slot, content);
		}		
	}
	
	// аналогично переопределяем метод удаления из слота
	@Override
	public void removeFromSlot(Object slot, IsWidget content) {
		if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) {
			leftColumn.remove(content);
		}
		else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){
			rightColumn.remove(content);
		}
		else {
			super.removeFromSlot(slot, content);
		}	
	}
}
</code>

Все довольно просто: setInSlot() принимает в себя презентер и соответствующий ему слот.
Мы просто указываем в какой виджет поместить этот презентер. В данном случае это две бутстраповские колонки leftColumn и rightColumn.
Хотя я повторюсь в данном случае уместней было бы помещать все в одну колонку, чтобы имитировать переход по страницам.

Далее наши презентер-виджеты и их вью:

<code class="java">public class FirstPagePresenter extends
		PresenterWidget<FirstPagePresenter.MyView> implements FirstPageUiHandlers, PopupEvent.Handler{

	public interface MyView extends View, HasUiHandlers<FirstPageUiHandlers> {
	}

	// попап с формой
	FirstPagePopupPresenter firstPagePopupPresenter;
	EventBus eventBus;
	
	@Inject
	public FirstPagePresenter(final EventBus eventBus, final MyView view,
			FirstPagePopupPresenter firstPagePopupPresenter ) {
		super(eventBus, view);
		this.firstPagePopupPresenter =  firstPagePopupPresenter;
		this.eventBus =  eventBus;
		getView().setUiHandlers(this);
		// назначаем себя хендлером PopupEvent
		eventBus.addHandler(PopupEvent.getType(), this);
	}

	@Override
	public void onShowFormBtnClicked() {
		// показываем всплывающее окно с формой
		showForm(true);		
	}

	private void showForm(boolean show) {
		if(show){
		addToPopupSlot(firstPagePopupPresenter, true);
		firstPagePopupPresenter.getView().show();
		}
		else {
			removeFromPopupSlot(firstPagePopupPresenter);
		}		
	}

	@Override
	public void onPopupEvent(PopupEvent event) {
		showForm(false);
		eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName()));		
	}
}
</code>

Обратите внимание что я заинжектил некий FirstPagePopupPresenter firstPagePopupPresenter.(код будет ниже). Это наше всплывающее окно с формой. Аналогично можно инжектить любые презентер-виджеты в любом количестве и с любой вложенностью. Главное не нарушать иерархию.

<code class="java">public class FirstPageView extends ViewWithUiHandlers<FirstPageUiHandlers> implements
		FirstPagePresenter.MyView {

	private final Widget widget;
	@UiField Button showFormBtn;

	public interface Binder extends UiBinder<Widget, FirstPageView> {
	}

	@Inject
	public FirstPageView(final Binder binder) {
		widget = binder.createAndBindUi(this);
		
		showFormBtn.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				getUiHandlers().onShowFormBtnClicked();				
			}
		});
	}

	@Override
	public Widget asWidget() {
		return widget;
	}
}
</code>

Во вью особо ничего интересного, кроме того, что оно наследует типизированный класс ViewWithUiHandlers.
Так как мы не хотим нарушать принципов MVP, то и не можем обращаться к презентеру напрямую из вью( наоборот можем). Для этого мы используем интерфейсы. О нажатии кнопки мы сообщаем с помощью getUiHandlers().onShowFormBtnClicked();

<code class="java">public interface FirstPageUiHandlers extends UiHandlers{

	void onShowFormBtnClicked();
}
</code>

getUiHandlers() возвращает нам интерфейс FirstPageUiHandlers, в котором мы указываем методы, которые должны быть реализованы в соответствующем презентере. Естественно что презентер должен имплементировать данный интерфейс, а вложенный в него интерфейс MyView должен наследовать типизированный интерфейс HasUiHandlers. И главное не забыть в презентере назначить себя обработчиком для событий вью — getView().setUiHandlers(this);

Далее презентер и соответствующий вью второй страницы:

<code class="java">public class SecondPagePresenter extends
		PresenterWidget<SecondPagePresenter.MyView> implements MainPageEvent.Handler {

	public interface MyView extends View {
		void showLoremIpsum();
		void showFormInfo(String firstName, String lastName);
	}
	
	EventBus eventBus;

	@Inject
	public SecondPagePresenter(final EventBus eventBus, final MyView view) {
		super(eventBus, view);
		this.eventBus =  eventBus;
		eventBus.addHandler(MainPageEvent.getType(), this);
	}
	
	@Override
	public void onMainPageEvent(MainPageEvent event) {
		switch(event.getAction()) {
		case SHOW_FORM_RESULT:
			showFormInfoWidget(event.getFirstName(), event.getLastName());
			break;
		case SHOW_LOREM_IPSUM:
			showLoremIpsumWidget();
			break;
		default:
			break;		
		}		
	}

	private void showLoremIpsumWidget() {
		getView().showLoremIpsum();		
	}

	private void showFormInfoWidget(String firstName, String lastName) {
		getView().showFormInfo( firstName, lastName);		
	}
</code>

<code class="java">public class SecondPageView extends ViewImpl implements
		SecondPagePresenter.MyView {

	private final Widget widget;
	
	@UiField FlowPanel contentPanel;

	public interface Binder extends UiBinder<Widget, SecondPageView> {
	}

	@Inject
	public SecondPageView(final Binder binder) {
		widget = binder.createAndBindUi(this);
	}

	@Override
	public Widget asWidget() {
		return widget;
	}

	@Override
	public void showLoremIpsum() {
		contentPanel.clear();
		contentPanel.add(new LoremIpsumWidget());				
	}

	@Override
	public void showFormInfo(String firstName, String lastName) {
		contentPanel.clear();
		contentPanel.add(new FormInfoWidget(firstName, lastName));	
	}
}
</code>

Тут особо ничего интересного и нового для разработчика на GWT. Общение между презентерами происходит посредством стандартных эвентов ( GwtEvent ).

И наконец попап с формой:

<code class="java">public class FirstPagePopupPresenter extends
		PresenterWidget<FirstPagePopupPresenter.MyView> implements PopupUiHandlers {

	public interface MyView extends PopupView , HasUiHandlers<PopupUiHandlers>{
	}

	EventBus eventBus;
	
	@Inject
	public FirstPagePopupPresenter(final EventBus eventBus, final MyView view) {
		super(eventBus, view);
		this.eventBus =  eventBus;
		getView().setUiHandlers(this);
	}

	@Override
	public void onSubmitBtnClicked(String firstName, String lastName) {
		eventBus.fireEvent(new PopupEvent(firstName, lastName));		
	}
}
</code>

<code class="java">public class FirstPagePopupView extends PopupViewWithUiHandlers<PopupUiHandlers> implements
		FirstPagePopupPresenter.MyView {

	@UiField PopupPanel main;
	@UiField Button submitBtn;
	@UiField TextBox firstName, lastName;

	public interface Binder extends UiBinder<Widget, FirstPagePopupView> {
	}

	@Inject
	public FirstPagePopupView(final EventBus eventBus, final Binder binder) {
		super(eventBus);
		binder.createAndBindUi(this);
                           main.setAnimationEnabled(true);
                           main.setModal(true);
                           main.setGlassEnabled(true);
                           submitBtn.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				getUiHandlers().onSubmitBtnClicked(firstName.getValue(), lastName.getValue());				
			}
		});
	}

	@Override
	public Widget asWidget() {
		return main;
	}
}
</code>

Как видно попап тоже является презентер-виджетом, но интерфейс его вью должен наследовать PopupView. И еще главная панель вью должна быть обязательно PopupPanel, ну или наследником данного класса. Еще одно отличие от обычных презентер-виджетов — чтобы показать попап на странице не нужен слот и панель для вставки. Достаточно использовать метод addToPopupSlot();

Также во всех связках презентер-вью использован uibinder. Соответствующие *ui.xml файлы я не выкладываю. Там в принципе ничего для GWT-разработчиков интересного нет.

Сам проект будет доступен некоторое время по этому адресу

И так а сейчас пробежимся по проекту что бы описать что происходит и как связаны презентеры между собой:

При загрузке MainPagePresenter в переопределенном методе onBind() мы сразу же ставим в слот презентер первой страницы:

<code class="java">	@Override
	protected void onBind() {
		super.onBind();
		getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter);	
	}
</code>

(Про жизненный цикл презентеров и методы onBind(), onUnbind, onReveal(), onReset(), onHide() я бы хотел рассказать в следующей статье.)

Соответственно в левой части экрана появляется вью FirstPagePresenter'a. При клике на кнопку мы вызываем имплементацию метода onShowFormBtnClicked() в FirstPagePresenter описанного в интерфейсе FirstPageUiHandlers

Вызов:
<code class="java">		showFormBtn.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				getUiHandlers().onShowFormBtnClicked();				
			}
		});
</code>

в FirstPagePresenter' e происходит следующее:

<code class="java">		addToPopupSlot(firstPagePopupPresenter, true);
</code>

Мы сетим презентер попапа в слот. Как я уже упоминал, для попапов слот не нужно определять. Единственное условие, что презентер из которого вызывается попап должен сам находится в слоте родителя и так далее по цепочке. Второй параметр в методе addToPopupSlot() указывает центровать ли попап в окне приложения(метод имеет несколько перегрузок и данный параметр в общем-то необязателен).

После того как попап появляется в окне, мы можем ввести туда какие-то данные и нажать кнопку подтверждения. Далее по аналогичной схеме вью попапа через getUiHandlers() вызывает обработчик в своем презентере, а тот в свою очередь кидает через EventBus эвент, на который подписан FirstPagePresenter (если кому-то интересно, то про эвенты в GWT я бы мог рассказать в следующей заметке):

<code class="java">	@Override
	public void onPopupEvent(PopupEvent event) {
		showForm(false);
		eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName()));		
	}
</code>

Сначала в методе showForm() мы удаляем попап из слота:

<code class="java">removeFromPopupSlot(firstPagePopupPresenter);
</code>

Затем кидаем новый эвент ( теперь это FirstPageEvent) дальше. На него подписан наш MainPagePresenter:

<code class="java">	@Override
	public void onFirstPageEvent(FirstPageEvent event) {
		// закрываем левый контент и открываем правый , в который  через эвент передаем имя и фамилию
		showRightContent();
		MainPageEvent mainPageEvent =  new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(),     event.getLastName());
		eventBus.fireEvent(mainPageEvent);
	}
</code>

Получив его MainPagePresenter удаляет из слота первую страницу и вставляет вторую:

<code class="java">	public void showRightContent() {
		removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter);
		getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter);	
	}
</code>

Далее он полылает уже MainPageEvent дальше. В него сетит не только имя и фамилию, но и Action.

Наш SecondPagePresenter получив эвент в методе onMainPageEvent() решает что показать на странице. В данном случае это обычные виджеты без презентеров.

<code class="java">	@Override
	public void onMainPageEvent(MainPageEvent event) {
		switch(event.getAction()) {
		case SHOW_FORM_RESULT:
			showFormInfoWidget(event.getFirstName(), event.getLastName());
			break;
		case SHOW_LOREM_IPSUM:
			showLoremIpsumWidget();
			break;
		default:
			break;		
		}		
	}
</code>

Вот собственно и все. Наверное, некоторым может показаться что для таких простых действий слишком много кода, но:
  • Мы не нарушаем принципов MVP — вью ничего не должно знать о своем презентере
  • Разделив приложение на модули код становится reusable и более гибким

Также наверняка некоторые возмутятся — зачем такие длинные цепочки передачи эвентов? Однако можно заметить, что получив эвент, презентер, перед отправкой следующего, делает какие-либо операции. Например, удаляет ненужные более презентеры или обрабатывает как-то полученные данные.

В общем надеюсь данная заметка окажется кому-либо полезной и он обратит свой взор в сторону GWT-Platform.

PS: Прошу прощения за некую сумбурность повествования и возможные ошибки. Это мой первый пост на IT-тематику. Обоснованная критика и советы очень приветствуются.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Крупное обновление ХабраРедизайнера


Всем привет, сегодня вышло обновление ХабраРедизайнера до версии 0.1.5.
Как и раньше, я потихоньку допиливаю дизайн и наращиваю функционал расширения.

Кратко
Исправлена куча ошибок, улучшена верстка, добавлены полезные , настройки и новый функционал.



Новое
  • В панель пользователя добавлена ссылка на страницу «Мои комментарии».
  • При нажатие на кнопку Поиска теперь появляется панель поиска
  • Добавлена ссылка на новые посты
  • Добавлены настройки

Верстка
  • Панель пользователя: Убран мусор, Добавлен стиль active
  • Панель уведомлений: Кнопки подстраиваются под количество уведомлений. Добавлен стиль hover
  • Убрана кнопка-ссылка «Создать топик»
  • Убрана кнопка «Хабрахабр» из панели справа

Исправление ошибок
  • Изменен способ загрузки css. Сайт перестал прыгать (Спасибо bo883)
  • Исправлена ошибка, иногда отправляющая по нажатию кнопки выхода на страницу настроек
  • Исправлены ошибки верстки: Панель рекомендаций теперь не наезжает на футер
  • В корпоративных блогах с измененным дизайном теперь отображается родная панель



Загрузить в магазине Chrome
Проект на ГитХабе

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Arduino watchdog или автоматический RESET в случае зависания


Речь пойдет о том, как держать Arduino всегда в работоспособном состоянии. Механизм watchdog встроен в Atmega, но, к сожалению, не всякий загрузчик (bootloader) Arduino правильно обрабатывает эту функцию. Попробуем разобраться с этой проблемой.

Итак, что такое watchdog? Простыми словами — это встроенный таймер на определенное время (до 8 сек в зависимости от чипа), который можно запустить программно. Как только таймер «дотикает» до нуля, контроллер подает правильный сигнал сброса (RESET) и всё устройство уходит в hard перезагрузку. Самое главное, что этот таймер можно сбрасывать в начальное состояние также программным способом.

  • Правильный сигнал сброса — достаточный по длительности для того, чтобы контроллер начал перегружаться. Иногда есть соблазн подключить к RST входу какой-либо цифровой выход Arduino и устанавливать его в 0 когда надо перегрузиться. Это плохой подход к решению проблемы, т.к. такого сигнала может быть недостаточно по времени, хотя и не исключено, что в некоторых случаях это тоже будет работать..
  • hard перезагрузка это самая настоящая перезагрузка, которая происходит при нажатии на кнопку RESET. Дело в том, что есть еще понятие soft перезагрузки — это программный переход на 0-вой адрес. В принципе, это тоже полезная вещь, но с помощью нее невозможно перегрузить зависший контроллер Ethernet или взглюкнувший LCD.
Короче говоря, встроенный watchdog это как раз то, что нужно и без дополнительных схем, пайки и соединений.

Функции Watchdog

Чтобы использовать функции Watchdog нужно подключить к проекту стандартную библиотеку:
<code class="cpp">#include <avr/wdt.h>
</code>
Теперь нам доступны следующие три функции:

1. Запуск таймера watchdog:
<code class="cpp">wdt_enable(WDTO_8S);
/* Возможные значения для константы
  WDTO_15MS
  WDTO_30MS
  WDTO_60MS
  WDTO_120MS
  WDTO_250MS
  WDTO_500MS
  WDTO_1S
  WDTO_2S
  WDTO_4S
  WDTO_8S
*/
</code>
Таймер будет считать ровно столько, сколько указано в константе. По истечении этого времени произойдет перезагрузка.

2. Сброс таймера watchdog:
<code class="cpp">wdt_reset();
</code>
Думаю, понятно для чего нужна эта функция — пока вы вызываете ее, контроллер не сбросится. Как только система зависнет и эта функция вызываться перестанет, то по истечении заданного периода произойдет перезагрузка.

3. Отключение watchdog:
<code class="cpp">wdt_disable();
</code>
Отключение таймера watchdog.

Собственно, на этом можно было бы и закончить наше повествование о watchdog… но дело в том, что все это работает только в Arduino Uno, а на Arduino Mega, Mini и Nano все это работает ровно наоборот, т.е. не работает совсем :)

Почему watchdog не работает на большинстве современных плат Arduino

Дело в том, что после перезагрузки, которая была вызвана watchdog, контроллеры последних выпусков оставляют включенным watchdog на минимальный период, т.е. 15ms. Это нужно для того, чтобы программа как-то узнавала, что предыдущая перезагрузка была по watchdog. Поэтому первоочередная задача загрузчика (или вашей программы, если она запускается первой) — сохранить информацию о том, что перезагрузка была «неожиданной» и сразу же выключить watchdog. Если этого не сделать, то система уйдет в bootloop, т.е. будет вечно перегружаться.

Как известно, в Arduino есть специальный загрузчик, который выполняется в первую очередь после перезагрузки системы. И, к огромному сожалению, стандартный загрузчик не сбрасывает watchdog! Таким образом, система заходит в жестокий bootloop (состояние «crazy led», при котором светодиод на 13-м пине мигает как сумасшедший).

Выглядит это все примерно так:

Пути решения проблемы

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

Для решения проблемы я даже прочитал man-ы самой платформы (:) и вроде бы там описана эта проблема и даже приведен код, который должен сделать всех счастливыми:

<code class="cpp">uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
void get_mcusr(void){
  mcusr_mirror = MCUSR;
  MCUSR = 0;
  wdt_disable();
}
</code>
Здесь описывается функция get_mcusr(), которая должна вызываться сразу после сброса. Это достигается макросом "__attribute__((section(".init3")))". Я пробовал прописывать эту функцию во все секции, которые только возможно — да, она действительно запускается до функции setup() из скетча, но, к сожалению, гораздо позже 15ms (минимальная константа watchdog) после сброса…

Короче говоря, как я ни рыл интернет в поисках легкого решения проблемы, так ничего найдено не было. Я нашел только один способ заставить watchdog работать — перепрошить загрузчик… чем мы сейчас и займемся.

Проверка работоспособности watchdog

Прежде чем что-то прошивать, нужно проверить — вдруг ваша Arduino поддерживает watchdog. Для этого я написал небольшой скетч для теста. Просто залейте его, откройте монитор порта и смотрите, что будет происходить.

Тестирование на watchdog
<code class="cpp">#include <avr/wdt.h>

void setup() {
  wdt_disable(); // бесполезная строка до которой не доходит выполнение при bootloop
  Serial.begin(9600);
  Serial.println("Setup..");
  
  Serial.println("Wait 5 sec..");
  delay(5000); // Задержка, чтобы было время перепрошить устройство в случае bootloop
  wdt_enable (WDTO_8S); // Для тестов не рекомендуется устанавливать значение менее 8 сек.
  Serial.println("Watchdog enabled.");
}

int timer = 0;

void loop(){
  // Каждую секунду мигаем светодиодом и значение счетчика пишем в Serial
  if(!(millis()%1000)){
    timer++;
    Serial.println(timer);
    digitalWrite(13, digitalRead(13)==1?0:1); delay(1);
  }
//  wdt_reset();
}
</code>

После перезагрузки (или подключения монитора к порту) встроенный светодиод мигнет, сигнализируя о том, что запустился загрузчик. Далее в секции setup происходит включение watchdog с таймером на 8 сек. После этого светодиод отсчитает нам это время и должна произойти перезагрузка.

Далее начинается самое интересное — если перезагрузка произошла и все повторяется в такой же последовательности, то вы имеете на руках Arduino, в которой загрузчик правильно обрабатывает watchdog. Если же после перезагрузки светодиод на 13-м пине начинает бесконечно мигать, то значит загрузчик не поддерживает watchdog. Здесь даже кнопка сброса не поможет. Для последующей прошивки нужно плату отключать от питания и после включения успеть прошить до первой перезагрузки.

Я протестировал 4 вида плат и только загрузчик в Arduino Uno сработал так как надо:

Платы Arduino

Результаты на мониторе
Watchdog не поддерживается загрузчиком:
image
Watchdog поддерживается загрузчиком:


Как легче всего прошить новый загрузчик?

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

Я не буду в этой статье описывать все премудрости создания программатора на основе Arduino, т.к. эта тема довольно подробно описана в интернете. В качестве программатора я использовал Arduino Uno. Как известно, прошивка производится через отдельный разъем ICSP, который есть почти на всех платах. В случае прошивки Arduino Pro Mini, у которого нет IСSP, подключение производится непосредственно к выводам.

Подключение для прошивки bootloaderimage
image

Где взять загрузчик, который поддерживает watchdog?

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

Рекомендуется использовать загрузчики из пакета optiboot. В принципе, эти загрузчики идут в инсталляции самой платформы Arduino, но лучше скачать и установить последнюю версию optiboot отсюда. Установка заключается в двух шагах (возможно, это можно сделать как-то по-другому):

  1. Папка bootloaders\optiboot перезаписывается в C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\optiboot
  2. Файл boards.txt дописывается к файлу C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt
Естественно, папка установки платформы Arduino у вас может быть другой.

Далее перегружается среда разработки и в меню Сервис/Плата можно наблюдать новые платы с пометкой [optiboot]. К сожалению, при выборе этих плат происходят какие-то непонятные ошибки компиляции и появляются всякие другие странности… поэтому делаем еще проще. Открываем в любом текстовом редакторе файл C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt и меняем следующие строчки:

Для Arduino Nano:
menu.cpu.nano.atmega328.bootloader.file=optiboot/optiboot_atmega328.hex

Для Arduino Mini:
menu.cpu.mini.atmega328.bootloader.file=optiboot/optiboot_atmega328.hex

Следующая проблема в том, что загрузчика optiboot для платы Arduino Mega не существует в природе, т.к. в Mega больше памяти и используется другой протокол. Поэтому мы используем стандартный, но модифицированный загрузчик, который качаем отсюда. Файл переименовываем в stk500boot_v2_mega2560_2.hex и записываем в папку C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\stk500v2.

Далее меняем в уже знакомом файле boards.txt следующую строчку:
mega2560.bootloader.file=stk500v2/stk500boot_v2_mega2560_2.hex

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

Процесс прошивки

После всех изменений можно прошивать загрузчики, выбирая в меню плат обычные платы (не [optiboot]!). В этом случае прошиваться будут именно те файлы hex, которые мы указали в файле board.txt.
Процесс прошивки может не стартовать и выдаваться ошибка:
<code class="cpp">avrdude: stk500_getsync(): not in sync: resp=0x00
</code>
Для решения этой проблемы откройте скетч программатора и в секции setup выберите другую скорость последовательного порта.
Во время заливки в Arduino Mega может появляться ошибка, которую следует игнорировать:
<code class="cpp">avrdude: verification error, first mismatch at byte 0x3e000
                               0x0d != 0xff
                      avrdude: verification error; content mismatch 
</code>

Заключительные манипуляции

Загрузчики optiboot имеют еще одну особенность — они увеличивают скорость загрузки скетчей, поэтому при использовании плат с optiboot нужно внести соответствующие изменения в boards.txt:

Для Arduino Nano:
menu.cpu.nano.atmega328.upload.speed=115200
Для Arduino Mini:
menu.cpu.mini.atmega328.upload.speed=115200

Предыдущую скорость порта лучше тоже запомнить, т.к. ее нужно будет использовать на платах со стандартными загрузчиками. Если такие изменения не сделать, то процессе заливки скетчей будет выдаваться ошибка, типа такой:
<code class="cpp">avrdude: stk500_getsync(): not in sync: resp=0x00
</code>

, литература

Пакет optiboot
Прошивка bootloader
Как прошить bootloader в Arduino Pro Mini

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[recovery mode] Недокументированные возможности недокументированных возможностей: Передача ref в другой поток

Никогда не приходил в голову вопрос: "а как сохранить/передать в другой поток ссылку на поле?"? Логичным предположением будет «передам ref в метод и сохраню. Стоп, oh shi~». Да, ref не сохраняются (а ещё, нельзя использовать на них замыкания, так что создать функцию внутри такого метода и создать из её поток тоже не получится). Но зато можно превратить ref в TypedReference с помощью недокументированного ключевого слова __makeref. Увы, TypedReference нельзя напрямую сохранить в поле ине наследует от System.Object, так что каст привычными методами тоже невозможен (да и вообще на их использование наложена целая куча ограничений). Казалось бы, тупик. Но это ещё не всё — есть ещё RuntimeArgumentHandle, который обладает свойствами TypedReference, за одним исключением — после хитрого каста в System.Object его ещё можно использовать до тех пор, пока жив кадр стека, в котором он был создан. Об этом этот пост.


TypedReference

Сам TypedReference удивительнейшая вещица — в него можно завернуть ref и передать другой метод (т.е. из метода, один из параметров которого является ref'ом). Однако, методы этой структуры не позволяют нам задавать значение — NotSupportedException ожидает нас на вызове соответствующих методов. Но не беда — имеется ключевое слово __refvalue, которое позволяет не только получить значение, но и задать его. Но выглядит это довольно странно:

<code class="cs">void Out(ref int someInt)
{
      Input(__makeref(someInt));
}

void Input(TypedReference @ref)
{
      int val = __refvalue(@ref, int);//Получаем значение
      __refvalue(@ref, int) = 0;//Задаём значение в someInt
}
</code>

При том, что тип задаётся ручками, скастить, например, int в string, не получится — проверка принадлежности типу все-таки проводится.
При этом всём, TypedReference тоже нельзя использовать в замыканиях — так что для того, чтобы создать что-то с замыканием на TypedReference тоже не получится.

RuntimeArgumentHandle

Является ничем иным, как params, только в профиль. По сути, представляет из себя некий список TypedReference'ов (доступ к которым производитс конструированием ArgIterator'а), а создаётся тоже… даже и не знаю как это описывать:

<code class="cs">void Out(int something)
{
      Input(__arglist(something));
}

void Input(__arglist)
{
       new ArgIterator(__arglist);
}
</code>

При этом, ключевое слово __arglist нельзя использовать в делегатах при их обьявлении. Но RuntimeArgumentHandle можно (но только как параметры, TypedReference и RuntimeArgumentHandle нельзя возвращать из методов). __arglist() также нельзя использовать как аргумент для вызова делегата, но зато __arglist можно. Смысл этой несколько расплывчатой формулировки лучше подкрепить примером:

<code class="cs">delegate void ArgWarrior(RuntimeArgumentHandle argh);

void Out(int something)
{
     (new ArgWarrior(u => { } ))(__arglist(someting));//не скомпилируется
     Input(new ArgWarrior(u => { } ), __arglist(someting);
}

void Input(ArgWarrior argh, __arglist)
{
       argh(__arglist);//а так можно
}
</code>

И вот я подобрался к ключевому моменту этого марлезонского балета: делегатам.

Манипуляции над _methodPtrAux как способ изысканных издевательств над делегатами

_methodPtrAux — это четвёртое поле в любом делегируемом типе, которое сыграет тут ключевую роль. В чём суть? Суть в том, что _methodPtrAux хранит в себе указатель на уже jit'енный метод. Записав произвольный неуправляемый код по тому указателю, можно таким образом этот неуправляемый код выполнить. Но это тут не главное. Делегат остаётся пригодным к использованию даже после подмены значения _methodPtrAux, и при вызове его, управление перейдёт именно туда, куда указывает значение этого поля. Т.о., имея два делегата с разными входными параметрами, я могу заменить указатель из делегата a на указатель из делегата b. Даже если у них разный набор аргументов, всё сработает. Ключевым моментом будет так-же и то, что даже если различаются типы соответствующих аргументов, clr не забьёт тревогу — int будет скастен в string все желания будут исполнены, никто не уйдёт обиженным, или… RuntimeArgumentHandle будет преобразован в System.Object:

<code class="cs">        delegate void Encast(RuntimeArgumentHandle @ref);
        delegate void Uncast(object @object);
        
       static void UseWith(Encast en, __arglist)
        {
            en(__arglist);
        }
        
       static object m_storedRef;
         
        static void Engage(ref object @object)
        {
             Encast en = new Encast(@ref => { });
             Uncast un = new Uncast(o =>
                {
                    m_storedRef = o;//сюда перейдёт управление после вызова <b>en</b>.
                });
                typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(en, typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(un));//меняем указатель у en
                UseWith(en, __arglist(__makeref(@object))); //вызываем
        }
</code>

Как видно по лямбде, я сразу уже сохраняю полученное значение в статическое поле. Да, тут есть одно непонятное ограничение — если сохранять o в не-статическое поле то можно уронить clr (чтение-запись защищённой памяти). Даже если целевым полем будет не поле, а поле обьекта, что хранится в статическом поле (например, Dictionary) всё должно пройти гладко. Несколько чудно при этом аргумент лямбды выглядит в отладчике: при просмотре можно увидеть только "{object}" (без кавычек) и ничего более. Попытка извлечь тип или привести к String при этом ничего хорошего не сулит (можно уронить clr)Скрытый текстЗато если такой фокус провернуть с TypedReference, можно увидеть ещё кое-что интересное (это я оставляю на самостоятельное изучение читателям. Можно попробовать скастить в int, тоже любопытно).
Обратное преобразование производится аналогично. Сохранение же кадра стека производится с помощью мониторов:

<code class="cs">      static object m_locker = new object();
      //...
     Monitor.Enter(m_locker);
     Monitor.Exit(m_locker);
</code>

m_locker уже заранее заблокирован из другого потока, так что выполнение приостанавливается, т.о. RuntimeArgumentHandle так и остаётся в стеке, не разрушаясь.
Полный код программы выглядит так:

<code class="cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadJiggler
{
    class Program
    {
        delegate void Encast(RuntimeArgumentHandle @ref);
        delegate void Uncast(object @object);
        static object m_storedRef;
        static object m_locker = new object();
        static bool m_useFlag;
        

        static void Main(string[] args)
        {
            object @v = "means \"vendetta\"";
            Victim1(ref @v);
            Console.WriteLine(@v);
        }

        static void UseWith(Encast en, __arglist)
        {
            en(__arglist);
        }

        static Thread m_someThread;

        static void Victim1(ref object @object)
        {
            Thread t = new Thread(() =>
            {
                Monitor.Enter(m_locker);
                {
                    for (; !m_useFlag; )
                    {
                        Thread.Sleep(10);
                    }

                    Encast en = new Encast(@ref =>
                    {
                        TypedReference tr = new ArgIterator(@ref).GetNextArg();
                        __refvalue( tr, object) = 0;
                    });

                    Uncast un = new Uncast(o => { m_storedRef = o; });
                    typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(un, typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(en));
                    un(m_storedRef);
                }
                Monitor.Exit(m_locker);
            });
            t.IsBackground = false;
            t.Start();

            {
                Encast en = new Encast(@ref => { });
                Uncast un = new Uncast(o =>
                {
                    m_storedRef = o; m_useFlag = true;
                    Monitor.Enter(m_locker);
                    Monitor.Exit(m_locker);
                });
                typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(en, typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(un));
                UseWith(en, __arglist(__makeref(@object)));
            }
        }
    }
}
</code>

В конце Main можно увидеть, что значение @v сменилось на 0.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Руководство по установке и настройке Web Deploy в среде Windows Server 2008 R2

В этом руководстве мы настроим Web Deploy в среде Windows Server 2008 R2 для простого развертывания приложений из Visual Studio 1 кликом мыши. Web Deploy позволяет настроить публикацию пользователем, не обладающим правами администратора.

Установка Web Deploy
Web Deploy можно установить двумя способами (мне именно так и пришлось).

Web Platform Installer
Первый способ через Web PlatfCL_Prefix_orm Installer. Его необходимо скачать и установить на сервер. Затем открыть и выбрать такие пункты как: Web Deploy, Web Deploy for Hosting Servers и IIS Recommendated Configuration (на скриншоте не видно)

Web PlatfCL_Prefix_orm Installer установка Веб Деплой

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

Установка через msi
Необходимо скачать файл установки Web Deploy (на сегодня версии 3.5) и установить его. При ручной установке необходимо будет вручную установить необходимые службы IIS. Делается это через панель управления сервером: Roles > IIS > Add Role Services

Добавление необходимые сервисов в IIS

Необходимо выбрать и установить следующие:
  1. Logging Tools
  2. Management Service (IIS Management Console может понадобиться)
После всех установок в панели IIS Manager должны появиться Features: Management Service, Management Service Delefation. Если устанавливаете Web Deploy вручную, необходимо в Management Service разрешить удаленное управление IIS:

IIS Management Service

Настройка сайта для удаленной публикации
После всех дейсвий должен был появиться пункт меню

Deploy Menu

Создаем пользователя не администратора и задаем ему сложный пароль. Также даем ему права на запись в папку сайта в wwwroot.
Далее настраиваем удаленную публикацию:

Настройка удаленной публикации Web Deploy

  1. Выбираем пользователя, с которым мы будем публиковать наш сайт;
  2. Указываем URL для публикации. Это должен быть внешний IP сервера с открытым портом по умолчанию 8172. При установке через WPI создается правило в Firewall и порт открывается.
  3. Указываем место, куда сохранить файл настроек.
  4. Нажимаем Setup
Получаем:
Publish enabled for 'WIN-9APS8Q11R9V\InDeploy'
Granted 'WIN-9APS8Q11R9V\InDeploy' full control on 'C:\inetpub\wwwroot\mysite'
Successfully created settings file 'C:\Users\Administrator\Desktop\WIN-9APS8Q11R9V_InDeploy.PublishSettings'

Проверить настройку можно перейдя по адресу в браузере, который мы указывали в настройке публикации вида: http://111.111.111.111:8172/msdeploy.axd — браузер должен предложить авторизоваться или написать что служба найдена, но мы не авторизованы.
Также необходимо проверить:
  • Служба msdepsvc запущена в автозапуске и работает сейчас net stop msdepsvc & net start msdepsvc
  • Аналогично служба wmsvc 
    net stop wmsvc & net start wmsvc
  • Также необходимо уточнить, возможен ли пинг до 80 порта (для службы Web Deployment Agent Service (MsDepSvc)) и 8172 для службы Web Management Service (WmSvc, handler).
  • Если публикация не настроена или возникают проблемы можно включить логи (Enabling Web Management Service Failed Request Tracing)

    Настройка публикации Web Deploy в Visual Studio
    После успешной настройки на стороне сервера необходимо настроить публикацию в Visual Studio. Для этого создаем профиль публикации, в методе публикации выбираем Web Deploy.

    Настройка веб деплой 1

    На следующем шаге выбираем конфигурацию Release. Здесь же можно указать строку подключения, на которую заменит VS при публикации (не пробовал). Получится удобная публикация решения в 1 клик:

    готовая настройка

    Важно: название сайта должно быть таким же как оно отображается в IIS Management.
    Важно: Если вы установили подписанный сертификат SSL на удаленном сервере, убедитесь, что вы установите флажок “Разрешить ненадежный сертификат” флажок. По умолчанию Web Deploy установит сертификат для вас, чтобы он был уникальный, однако он будет самоподписанный.
    Также есть настройка, которая позволяет уточнить «Оставлять ли лишние файлы или нет». Веб деплой будет копировать только изменившиеся файлы с момента последней публикации.

    Резюме
    Web Deploy предоставляет мощный и гибкий инструмент автоматизированного развертывания приложений ASP.NET на удаленном сервере. Кроме того, он позволяет публиковать не только файлы но и схемы базы данных и скрипты обновления и скрипты настройки параметров ACL (Access Control List)
    Можно использовать Visual Studio, чтобы автоматически публиковать решения на сервер или же создать Web Deploy Package и вручную установить необходимые обновления на сервере.
    Надеюсь с этим руководством станет проще публиковать свои сайты.




    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Дайджест новостей из мира мобильной разработки за последнюю неделю №22 (26 августа — 1 сентября 2013)

    Мы, наконец, все вернулись из отпусков, и продолжаем выпуск наших дайджестов. На этой неделе писали о том, как легально работать с Google Play, Unity 3D стал 2D и предложил ряд новых сервисов, США теряют свое лидерство на рынке приложений — он становится поистине глобальным.



    Лучшее

    Google Play — работаем легально!
    Рассказ о том как сделать свое хобби по разработке Android-приложений пусть небольшим, но официальным бизнесом. О том, как легально получать деньги, заработанные на Google Play, о «страшном» валютном контроле и «таинственном» паспорте сделки. .
    Unity: 2D, реклама и издательство
    На конференции UNITE в Ванкувере глава компании Дэвид Хельгасон анонсировал три новинки самого популярного игрового движка, который используют уже более 400 000 человек: официальную поддержку 2D игр, встроенный рекламный сервис Unity Cloud и новое издательское отделение компании Unity Games.
    Ужесточение правил для разработчиков Google Play. Полный запрет push-рекламы
    Компания Google выпустила крупное обновление правил программы для разработчиков приложений для Google Play. Неважно, кто вы — пользователь или разработчик — следует знать об этих изменениях.
    США теряют позиции на мировом рынке приложений
    Согласно новым результатам исследования от аналитической фирмы Flurry, опубликованным этим утром, США больше не является лидером по количеству созданных приложений, доля страны на мировом рынке приложений снизилась с 45% в 2011 году, до 36% в 2013.

    Android
    iOS
    Windows Phone
    BlackBerry
    Firefox OS
    Разработка
    Деньги и маркетинг
    Устройства


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Adobe AIR + Nape Physics. Разработка под iOS

    Итак, недавно я купил Mac mini, т.к. давно мечтал заняться портированием одной из своих игрушек под iOS. Вопрос стал в выборе платформы, и я какое-то время склонялся к Adobe Air, пока не копнул глубже…



    На днях у нас была локальная «конференция» из пяти человек в одном из питерских баров KillFish. И там мы обсудили мельком и Air, и Unity, и Cocos2d, и прочее… Я голосовал за AIR, т.к. думал, что раз уж «Angry Birds: Star Wars» сделана на Starling + Air, и она летает с приличным количеством физики и эффектов — значит, это мой выбор! Тем более, многие видели демки на Starling, где в iOS мы наблюдаем сотни анимированных объектов со стабильными 60 fps. Но на деле… всё упирается в физику.



    Разработчик по имени Павел посеял во мне зерно сомнения, высказав свою неуверенность по части причастности AIR к Angry Birds — Star Wars. Придя домой, я скачал с торрентов .apk файл энгри бёрдов, переименовал в .zip, и обнаружил всё то, чего быть в AIR-версии просто не может: уровни в .lua, ассеты в .pvr и .zip, и прочие непотребства. Оказалось, на AIR делали всего лишь версию для Facebook. В довершении я скачал все фреймворки из заголовка, открыл IntelliJ IDEA, подключил сертификаты от Apple, и сделал простую демку для теста производительности физики. Результаты огорчили…

    Чтобы получились честные 60 fps:

    iPhone 4 — тянет всего 15-20 динамических тел.
    iPad 1 — 20-25.
    iPad mini — до 45.

    Многие, конечно, делают и во флешках 24-30 fps. Но это не наш метод. Конечно, если выставить 30 fps, на том же iPhone 4 можно будет использовать до 40 физ.тел.

    Что мы получаем в итоге:

    1. AIR подходит для игр без физики, GPU вполне тянет большое количество графики.
    2. AIR + Nape подходит для игр с физикой, при условии небольшого количества тел (20 тел — 60 фпс).
    3. AIR + Nape подходит для нединамичных игр с физикой, при условии занижения фпс (40 тел — 30 фпс).



    Какие выводы можно сделать? Утверждать, что AIR не подходит для iOS игр — нельзя. Можно делать фермы, тауэр дефенсы, матч3 и прочие пазлы, платформеры и ещё кучу всего. Можно делать даже игры с физикой, при условии небольшого количества тел и заниженного фпс. Но вот когда вам нужно сделать динамичную игру на 60 фпс с нормальным количеством физ.объектов — AIR сдаёт позиции.

    Посмотрев на свои игры, я понял, что AIR подходит далеко не для всех. Laser Cannon, который я планировал портировать, теперь будет лежать в ящике до выхода Unity 2D (что обещают уже совсем скоро):


    Инфа о Unity 2D — http://blogs.unity3d.com/2013/08/28/unity-native-2d-tools/.

    Видюшка вдохновила. Как и инфа, что Unity для iOS девелоперов теперь абсолютно бесплатная (не Pro версия, само собой). Так что, расстраиваться, в принципе, нечему. C# я люблю не меньше ActionScript 3.0.

    Смотрим, читаем, экспериментируем… делаем выводы.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Закрыт TJournal

    Первый день осени начался с плохой новости. На данный момент закрыт популярный ресурс TJournal. При посещении сайта посетителям показывается вот такая заглушка:



    На данный моент сложно сказать, что произошло, но судя по всему, возможной причиной закрытия ресурса стал конфликт между его командой. Технический директор TJournal, Илья Чекальский, на своей странице в социальной сети ВКонтакте опубликовал следующий пост:
    image
    Который, как видно выше, негативно прокомментировал главный редактор и сооснователь TJournal — Никита Лихачев (за информацию о должности Лихачева спасибо leonaded).

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

    И судя по всему восстановления работы сервиса ждать не стоит.
    image

    Очень жаль, что такое происходит. Будем надеятся, что ресурс все-таки вернется к своей работе.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Фильтры исключений в CLR

    Привет, хабралюди. Сегодня мы рассмотрим один из механизмов CLR, который напрямую недоступен для разработчиков на языке C# — фильтры исключений.

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

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

    Под катом — код на VB.NET, F#, CIL и C#, а также проверка различных декомпиляторов на обработку механизма фильтров.

    Откуда есть пошли фильтры исключений

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



    На этапе поиска подходящего блока
    catch CLR выполняет обход своего внутреннего стека обработчиков исключений, а также выполняет фильтры исключений. Обратите внимание — это происходит до выполнения кода в блоке finally
    . Мы обсудим этот момент позже.

    Как это выглядит на VB.NET
    Фильтры исключений нативно поддерживаются языком VB.NET. Вот пример того, как выглядит код, использующий фильтры:

    <code class="vbscript">Sub FilterException()
    	Try
    		Dim exception As New Exception
    		exception.Data.Add("foo", "bar1")
    
    		Console.WriteLine("Throwing")
    		Throw exception
    	Catch ex As Exception When Filter(ex) ' здесь фильтр
    		Console.WriteLine("Caught")
    	Finally
    		Console.WriteLine("Finally")
    	End Try
    
    End Sub
    
    Function Filter(exception As Exception) As Boolean
    	Console.WriteLine("Filtering")
    	Return exception.Data.Item("foo").Equals("bar")
    End Function
    </code>

    При выполнении данного кода будет выдана следующая цепочка сообщений:

    <code class="dos">Throwing
    Filtering
    Caught
    Finally
    </code>

    Как это выглядит в F#
    При подготовке статьи я нашёл в интернете информацию о том, что F# поддерживает фильтры исключений. Что ж, проверим это. Вот пример кода:

    Код на F#
    <code class="scala">open System
    
    let filter (ex : Exception) =
        printfn "Filtering"
        ex.Data.["foo"] :?> string = "bar"
    
    let filterException() =
        try
            let ex = Exception()
            ex.Data.["foo"] <- "bar"
            printfn "Throwing"
            raise ex
        with // дальше фильтр
        | :? Exception as ex when filter(ex) -> printfn "Caught"
    
    [<EntryPoint>]
    let main argv = 
        filterException()
        0
    </code>


    Этот код компилируется без фильтров, с обычным
    catch [mscorlib]System.Object. Мне так и не удалось заставить компилятор F# сделать фильтр исключений. Если вам известны альтернативные способы это сделать — добро пожаловать в комментарии.

    Как это выглядит в CIL
    CIL (Common Intermediate Language) — это аналог низкоуровневого языка ассемблера для .NET-машины. Скомпилированные сборки можно дизассемблировать в этот язык с помощью инструмента ildasm
    , и собирать обратно с помощью
    ilasm, которые поставляются вместе с .NET.

    Приведу фрагмент кода на VB.NET, каким я его увидел в ildasm
    :

    Много кода на CIL
    <code class="scala">.method public static void  FilterException() cil managed
    {
      // Code size       110 (0x6e)
      .maxstack  3
      .locals init ([0] class [mscorlib]System.Exception exception,
               [1] class [mscorlib]System.Exception ex)
      IL_0000:  nop
      IL_0001:  nop
      .try
      {
        .try
        {
          IL_0002:  newobj     instance void [mscorlib]System.Exception::.ctor()
          IL_0007:  stloc.0
          IL_0008:  ldloc.0
          IL_0009:  callvirt   instance class [mscorlib]System.Collections.IDictionary [mscorlib]System.Exception::get_Data()
          IL_000e:  ldstr      "foo"
          IL_0013:  ldstr      "bar"
          IL_0018:  callvirt   instance void [mscorlib]System.Collections.IDictionary::Add(object,
                                                                                           object)
          IL_001d:  nop
          IL_001e:  ldstr      "Throwing"
          IL_0023:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_0028:  nop
          IL_0029:  ldloc.0
          IL_002a:  throw
          IL_002b:  leave.s    IL_006b
        }  // end .try
        filter
        {
          IL_002d:  isinst     [mscorlib]System.Exception
          IL_0032:  dup
          IL_0033:  brtrue.s   IL_0039
          IL_0035:  pop
          IL_0036:  ldc.i4.0
          IL_0037:  br.s       IL_0049
          IL_0039:  dup
          IL_003a:  stloc.1
          IL_003b:  call       void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception)
          IL_0040:  ldloc.1
          IL_0041:  call       bool FilterSamples.VbNetFilter::Filter(class [mscorlib]System.Exception)
          IL_0046:  ldc.i4.0
          IL_0047:  cgt.un
          IL_0049:  endfilter
        }  // end filter
        {  // handler
          IL_004b:  pop
          IL_004c:  ldstr      "Caught"
          IL_0051:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_0056:  nop
          IL_0057:  call       void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
          IL_005c:  leave.s    IL_006b
        }  // end handler
      }  // end .try
      finally
      {
        IL_005e:  nop
        IL_005f:  ldstr      "Finally"
        IL_0064:  call       void [mscorlib]System.Console::WriteLine(string)
        IL_0069:  nop
        IL_006a:  endfinally
      }  // end handler
      IL_006b:  nop
      IL_006c:  nop
      IL_006d:  ret
    } // end of method VbNetFilter::FilterException
    </code>


    Как видно, компилятор VB.NET, конечно, сильно расписал наш код в виде CIL. Больше всего нас интересует блок
    filter:

    <code class="scala">filter { // Проверяем, что брошенный объект является экземпляром System.Exception: IL_002d: isinst [mscorlib]System.Exception IL_0032: dup IL_0033: brtrue.s IL_0039 IL_0035: pop IL_0036: ldc.i4.0 // Если нет - то выходим: IL_0037: br.s IL_0049 IL_0039: dup // Тут какой-то служебный вызов: IL_003a: stloc.1 IL_003b: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) // Вызываем функцию, которую мы определили как фильтр: IL_0040: ldloc.1 IL_0041: call bool FilterSamples.VbNetFilter::Filter(class [mscorlib]System.Exception) IL_0046: ldc.i4.0 IL_0047: cgt.un IL_0049: endfilter } // end filter </code>
    Итак, компилятор вынес в блок фильтра проверку типа исключения, а также вызов нашей функции. Если в конце выполнения блока фильтра на стеке лежит значение 1
    , то соответствующий этому фильтру блок
    catch будет выполнен; иначе — нет.

    Стоит отметить, что компилятор C# проверки типов не выносит в блок filter
    , а использует специальную CIL-конструкцию
    catch с указанием типа. То есть, компилятор C# не использует механизм filter
    вообще.

    Кстати говоря, для генерации этого блока можно использовать метод ILGenerator.BeginExceptFilterBlock (если вы пишете свой компилятор).

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

    Последний JetBrains dotPeek 1.1 при попытке декомпиляции сборки с фильтром радостно сообщил следующее:

    <code class="cs">public static void FilterException()
    {
      // ISSUE: unable to decompile the method.
    }
    </code>

    .NET Reflector 8.2 поступил более адекватно и что-то смог декомпилировать в C#:

    <code class="cs">public static void FilterException()
    {
        try
        {
            Exception exception = new Exception();
            exception.Data.Add("foo", "bar");
            Console.WriteLine("Throwing");
            throw exception;
        }
        catch when (?)
        {
            Console.WriteLine("Caught");
            ProjectData.ClearProjectError();
        }
        finally
        {
            Console.WriteLine("Finally");
        }
    }
    </code>

    Что ж, неплохо — хотя код и некомпилируемый, но по нему хотя бы видно наличие фильтра. То, что фильтр не был расшифрован, можно списать на недостатки C#-транслятора. Попробуем то же самое с транслятором в VB.NET:

    <code class="vbscript">Public Shared Sub FilterException()
        Try 
            Dim exception As New Exception
            exception.Data.Add("foo", "bar")
            Console.WriteLine("Throwing")
            Throw exception
        Catch obj1 As Object When (?)
            Console.WriteLine("Caught")
            ProjectData.ClearProjectError
        Finally
            Console.WriteLine("Finally")
        End Try
    End Sub
    </code>

    Увы, попытка точно так же провалилась — декомпилятор почему-то не смог определить имя фильтрующей функции (хотя, как мы видели выше,
    ildasm с этим прекрасно справился).

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

    Чем это отличается от проверок в теле блока catch

    Рассмотрим фрагмент кода, почти аналогичный коду на VB.NET:

    Код на C#
    <code class="cs">static void FilterException()
    {
    	try
    	{
    		var exception = new Exception();
    		exception.Data["foo"] = "bar";
    		Console.WriteLine("Throwing");
    		throw exception;
    	}
    	catch (Exception exception)
    	{
    		if (!Filter(exception))
    		{
    			throw;
    		}
    
    		Console.WriteLine("Caught");
    	}
    }
    
    static bool Filter(Exception exception)
    {
    	return exception.Data["foo"].Equals("bar");
    }
    </code>


    А теперь попробуем найти разницу в поведении между примерами на C# и VB.NET. Всё достаточно просто: выражение
    throw; в C# теряет номер строки в стеке. Если изменить фильтр так, чтобы он возвращал false
    , то приложение упадёт с сообщением

    <code class="dos">Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown.
       at CSharpFilter.Program.FilterException() in CSharpFilter\Program.cs:line 25
       at CSharpFilter.Program.Main(String[] args) in CSharpFilter\Program.cs:line 9
    </code>

    Судя по стеку, исключение было сгенерировано на 25 строке (строка
    throw;), а не на строке 19 (throw exception;
    ). Код на VB.NET в таких же условиях показывает изначальное место выпадения исключения.

    UPD. Изначально я ошибочно написал, что
    throw; теряет весь стек, но в комментариях подсказали, что это действительно совсем не так. Происходит лишь незначительная модификация номера строки в стеке. Причём на mono это не воспроизводится — стек исключения там не меняется после throw;
    (спасибо kekekeks за эти подробности).

    О безопасности

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

    Коротко: если вы выполняете временное повышение привилегий для какого-то внешнего и потенциально разрушительного кода, то нельзя полагаться на
    finally, т.к. перед выполненнием блока finally
    могут быть вызваны фильтры исключений, расположенные выше по стеку вызовов (а злоумышленник может вытворять в коде этих фильтров всё, что ему вздумается). Помните — поиск подходящего блока
    catch всегда выполняется до выполнения блока finally
    .

    Заключение

    Сегодня мы рассмотрели один из редко встречаемых программистами на C# механизмов среды CLR. Сам я не пишу на VB.NET, но считаю, что эта информация может быть полезна всем разработчикам .NET-платформы. Ну а если вы занимаетесь разработкой языков, компиляторов или декомпиляторов для этой платформы, то вам тем более эта информация пригодится.

    PS. Код, картинки и текст статьи выложены на github: github.com/ForNeVeR/ClrExceptionFilters.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    NNM-Club под угрозой блокировки и готовится к ней, а Rutor и Opensharing незаконно удерживаются в Реестре

    image

    Мосгорсуд 30 августа вынес 2 решения по обеспечительной блокировке крупного интернет-портала «NoNaMe Club».
    Оба заявления были поданы от лица ООО «Централ Партнершип Сейлз Хаус», который до сего времени еще не предъявлял претензии по 187-ФЗ к какому-либо ресурсу.

    И вот, сквозь привычные «звёздочки» в тексте постановлений проглядываются на новую цель т.н. правообладателей:

    Заявление ООО «Централ Партнершип Сейлз Хаус» о принятии предварительных обеспечительных мер, направленных на обеспечение защиты прав лицензиата, полученных им на основании исключительной лицензии, на аудиовизуальные произведения: «Легнда №17», «Легенды о круге», «Марафон», «Пять невест», «О чем молчат девушки», «Ликвидация», размещенные на сайте информационно — телекоммуникационной сети «Интернет» *** – удовлетворить.

    Обязать Федеральную службу по надзору в сфере связи, информационных технологий и массовых коммуникаций и иных лиц прекратить создание технических условий, обеспечивающих размещение, распространение и иное использование аудиовизуальных произведений: «Легнда №17», «Легенды о круге», «Марафон», «Пять невест», «О чем молчат девушки», «Ликвидация» на сайте информационно-телекоммуникационной сети «Интернет» ***.
    Установить процессуальный срок продолжительностью пятнадцать дней со дня вынесения настоящего определения для подачи ООО «Централ Партнершип Сейлз Хаус» искового заявления по требованию, в связи с которым судом приняты меры по обеспечению имущественных интересов заявителя.

    Следует отметить ряд моментов:
    1) Непонятно зачем в отношении nnm-club были вынесены 2 аналогичных решения под копирку, содержащих причём одни и те же ошибки.
    2) Как вам в решении суда, например, указание на какой фильм: «Легнда №17»? В таком виде данное наименование было указано 4 раза в одном тексте.
    3) В определении Мосгорсуда стоит ссылка на домен
    http://nnm-club.ru/, но это всего лишь редирект на текущий домен портала nnm-club: http://nnm-club.me/


    image

    По выявленному факту вынесения решения Мосгорсудом, на портале NoNaMe Club развернулась широкая дискуссия что делать дальше.
    И волшебным образом на заглавной странице вновь появилась июльская тема "Готовимся к блокировкам сайтов", в шапке которой даются пояснения о 8 способах обхода блокировки.
    Хотя официальной позиции от портала пока нет, но думаю это прямой намёк.

    Аналогичные темы созданы на тех ресурсах, которые уже находятся в Реестре по блокировкам Роскомнадзора: Rutor.org даёт пояснения о "Рекомендованных методах обхода блокировок", в том же ключе действует и ресурс Opensharing.org.
    Также, напомню, что последний разъяснил свою официальную позицию на Хабре

    Снова хочу обратить внимание Роскомнадзора, что срок обеспечительных мер по блокировке начинает отсчитываться с момента вынесения определения судом, т.е. в данном случае в отношении NNM-Club — с 30 августа. И неважно каким именно днем регулятор внесет данный интернет-ресурс в свой Реестр, 14 сентября он должен будет его исключить из-под блокировки в том случае, если правообладателем не будет подан полноценный иск.

    Также напомню, что сроки обеспечительных мер по тем ресурсам, которые подвергаются в настоящее время блокировке (Rutor.Org и Opensharing.org) уже давно истекли (21 и 27 августа соответственно), но они продолжают находиться в Реестре, который отсылается оператором для ограничения доступа к ресурсам.

    Роскомнадзор по-прежнему не дает разъяснений на этот счет и игнорирует четкое определения решений суда согласно нормам 187-ФЗ.
    Фактов подачи исков истцами-правообладателями не установлено. По крайней мере, ни Мосгорсуд об этом не дает информацию на своем ресурсе, ни в ГАС «Правосудие», ни в системе арбитражных дел данные иски не значатся.

    По материалам:
    «РосКомСвобода»
    "Новая цель «антипиратского» закона — NNM-Club",
    "Почему не снимается обеспечительная блокировка?",
    «NNM-Club»
    "Готовимся к блокировкам сайтов",
    «Rutor»
    "Информация по блокировкам",
    «Opensharing»
    "Блокировка по антипиратскому закону!",
    "Официальная позиция"

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


    Как вы считаете, как должны поступать интернет-ресурсы после вынесенных Мосгорсудом решений по блокировке


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 1497 человек. Воздержалось 526 человек. Источник: habrahabr.ru,
    получено с помощью rss-farm.ru




    Должны удалять спорный контент и ссылки на него и больше не предпринимать никаких иных публичных действий



    Должны удалять контент, но при этом стараться оспаривать решения Мосгорсуда и действия Роскомнадзора



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



    Не должны удалять контент и не надо им предпринимать никаких иных публичных действий



    Не должны удалять контент и при этом стараться оспаривать решения Мосгорсуда и действия Роскомнадзора



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



    Другое, я сейчас расскажу как разрулить ситуацию

    Добываем исходный код VM/370

    Здравствуйте, уважаемые хабарчане!
    Почти неделю назад я написал свой первый пост о VM/370. Первым комментарием к нему было совершенно справедливое замечание:
    Весело, конечно, но «полотно» состоит в основном из выводов команд. Если честно, гораздо интереснее прочитать не только про саму установку системы, но и про её «кишки», как, что, да почему.
    Исследовать исходники VM/370, к примеру.
    Да, действительно, туториал по установке мягко говоря устаревшей ОС интересен только в общепознавательном плане как демонстрация ее возможностей. А вот описание принципов работы с цитатами из исходников — другое дело. Тем более, что исходники доступны. Проблема только в том, что подобное описание — дело серьезное.
    Принципы работы VM/370 описаны в этом трехтомнике. Сам исходный код — сравнительно небольшой, «всего» двести тысяч строк на ассемблере — CP и примерно столько же — . Но работа все равно предстоит капитальная.
    В этой статье я не ставлю перед собой задачу даже начать цикл о внутренностях VM/370. Я только объясню как я извлек исходный код VM/370 в читабельном формате. В процессе извлечения я узнал кое-что интересное про работу с VM/370.


    Распаковка ленты в CMS

    Объем ленты с исходниками — около тридцати мегабайт. Будучи совершенно уверенным что файлы хранятся на ленте в несжатом виде, я просто разделил этот объем на емкость цилиндра 3330 и вычислил, что для сохранения всех исходников мне понадобиться 130 цилиндров. Потом это конечно оказалось не так (видимо, какое-то сжатие все-таки происходит, размер распечаток — ок. 40 мегабайт), но к счастию лента состояла из нескольких томов, и я просто распечатал их один за другим.
    Итак, добавим в каталог, в описание пользователя MAINT, строку:
    <code class="bash"> MDISK 192 3330 200 130 CPR6L0 WR READ * SOURCES
    </code>
    Примечание: весь процесс я выполнял под пользователем MAINT. Вообще говоря, это — злостное нарушение правила «не работай под рутом» и так делать нельзя.
    Запустим VM, залогинимся как MAINT, запустим CMS. введем перфокарты с описанием каталога и обновим его командой «DIRECT MYVM». Перелогинимся (чтобы изменения учетной записи вступили в силу). Подключим диск 192 (командой «access 192 b») и ленту с исходниками. Загрузим первый том архива (исходники CP) командой «VMFPLC2 LOAD * * B».

    Распечатка

    Я долго не мог найти способ распечатать несколько файлов одной командой. Дело в том, что команды PRINT и PUNCH ругаются на звездочки в имени файла. А печатать пятьсот штук файлов вручную что-то не хотелось. В конце-концов я решил, что проще всего будет написать программу распечатки на ассемблере, но роясь в мануалах по ассемблеру, нашел более легкий способ.
    У команды LISTFILE (аналог DIR/ls) есть опция (EXEC. Если запустить LISTFILE с этой опцией, LISTFILE создаст файл (файлы EXEC — это аналог bat/sh), со строками вида &1 &2. &1 &2 — это параметры скрипта.
    Теперь внимание! При запуске команды CMS PUNCH, в каждой строке файла CMS EXEC вместо &1 будет подставлен PUNCH, а затем строка выполнена. По-моему, это самое лучшее решение инженеров IBM в области пользовательского интерфейса (хотя и ненужное в Linux при наличии awk).
    Я поэкспериментировал с различными распечатками и решил, что PUNCH лучше чем PRINT.
    Примечание: геркулесовский вывод перфокарт настроен на формат EBCDIC. Чтобы получить читабельный код, надо перенастроить его на ASCII командой «ATTACH D ./sources/DMK.txt ascii».
    Итак, создаем список файлов:
    <code class="bash">L * * B (EXEC
    </code>
    И выводим их:
    <code class="bash">CMS PUNCH
    ...длинный список файлов.
    </code>
    Уже когда все закончилось, я догадался, что имело смысл добавить в CMS EXEC первую строчку &CONTROL OFF (аналог echo off). Да, не застал я не то что VM/370, но даже и элементарный MS-DOS.

    Разделение файлов

    В результате предыдущих манипуляций, я получил файл DMK.txt со склеенными вместе исходниками. Теперь их надо разделить. Для этого я применил такой скрипт на awk:
    <code class="bash">/^MAINT    MAINT    MAINT    MMMM  AAAA  IIII  NNNN  TTTT$/ {next}
    /^USERID/ {next}
    
    $1==":READ"{
        MYFILE="./DMK/"$2 "_" $3
        next
      }
    
    {
      print $0 > MYFILE
    }
    </code>
    Прошу прощения за г-код, писалось на коленке и не с целью читабельности/эффективности.

    Теперь таким же образом можно вывести исходники CMS (условный код DMS), RSCS (условный код DMT, название Remote Spooling Communication Subsystem немного путает, но это в каком-то смысле аналог fido) и IPCS (условный код DMM, системные тесты).



    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Посты-рекордсмены. Продолжение

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

    В предыдущем посте (Посты-рекордсмены / Хабрахабр), я пробовал различные варианты сортировки постов Хабра, отличные от обычного рейтинга. В этом я буду сортировать по рейтингу, но не все посты, а отобранные по определённым критериям.

    Как я уже писал, сравнивать рейтинг постов, написанных в разные годы — неправильно, т.к. колличество пользователей и соответственно читателей постоянно росло и если сейчас рейтинг, к примеру, 200, у поста — довольно обычное дело, то в 2006ом и в 2007ом году постов с таким рейтингом просто не было. Вообще. По этому поводу, топ-10 по годам с 2006го по 2009й, дела давно минувших дней, преданья старины глубокой:

    2006
    Опубликовано руководство по дизайну Веб 2.0 / Хабрахабр
    Тим О’Рейли: Движение в новую реальность / Хабрахабр
    Хабражест хабрамышкой / Хабрахабр
    Ты стал Человеком Года по версии Time / Хабрахабр
    Google Search Quality запрещает обмен ссылками и рекомендует SMO / Хабрахабр
    Десять гаджетов, которые изменили мир / Хабрахабр
    Типовые менеджерские ошибки, совершаемые заказчиком при разработке сайта / Хабрахабр
    Деньги как средство нематериального поощрения / Хабрахабр
    «Бегун» начинает принимать любые сайты / Хабрахабр
    Молоко и яйца: улыбайтесь, вас покупают! / Хабрахабр

    2007
    Эксперименты с Мамбой. Часть 1. / Хабрахабр
    The Scene — настоящий андеграунд Интернета / Хабрахабр
    Программирование как искусство / Хабрахабр
    Дом Яндекса на Самокатной / Хабрахабр
    Скоропостижно ушёл из жизни Антон Скоробогатов / Хабрахабр
    Делаем логотип LG / Хабрахабр
    Новый сервис от Google / Хабрахабр
    Давайте убьем IE6 / Хабрахабр
    Word придумал Штирлиц? Информация к размышлению / Хабрахабр
    Полезные мелочи программирования на PHP / Хабрахабр

    2008
    «Яндекс.Деньги» массово закрывает счета украинских пользователей. / Хабрахабр
    Мал, да удал: Trojan-Downloader.Win32.Tiny / Хабрахабр
    Почему iPhone 3G провалился в России / Хабрахабр
    QIP 2008 concept / Хабрахабр
    Государство ворует мои деньги / Хабрахабр
    Конец холивара! / Хабрахабр
    Совестно быть пиратом… / Хабрахабр
    Микросайтинг / Хабрахабр
    ТОП 10 самых раздражающих факторов для программиста / Хабрахабр
    Сравнение Nokia 3310 и iPhone 3G / Хабрахабр

    2009
    Были получены исходники 3300 глобальных интернет-проектов / Хабрахабр
    О том, что сегодня произошло с «аськой» (часть 1-я) / Хабрахабр
    Мощный лазер своими руками за один вечер / Хабрахабр
    Памятка дизайнеру сайтов / Хабрахабр
    Верни мои деньги, банкомат! / Хабрахабр
    Пиратская локализация. Как это было / Хабрахабр
    Что я нашёл интересного на почтовом сервере метеорологов / Хабрахабр
    Ломаем каптчу Яндекса / Хабрахабр
    Безвыходных ситуаций не бывает / Хабрахабр
    QIP — Минутка ненависти (хистори на сервере) / Хабрахабр

    Теперь выполню пару «заказов», пришедших в личку после публикации предыдущего поста.
    Идеи принадлежат Budda40 и cigulev.

    В какой-то момент на Хабре появились флажки «Из песочницы», «Перевод», «Тьюториал», «Рекавери». Топы по флажкам.

    Песочница (лучшие дебюты)
    Топик якобы из песочницы / Хабрахабр
    Как я наказал Firaxis или история о том, как перебрать бинарный движок через глушитель / Хабрахабр
    Бейджи для Хабра, версия / Хабрахабр
    Клавиатура, идея, две руки / Хабрахабр
    Безопасность интернет ресурсов — взлом сайта rospil.info / Хабрахабр
    Сказ о том, как один нерадивый провинциал в MIT поступал / Хабрахабр
    HOWTO: свой бизнес в США из России / Хабрахабр
    13 причин не быть управленцем / Хабрахабр
    Подделываем вашу подпись при помощи шарнирного механизма. Теорема Кемпе / Хабрахабр
    Получаем изображение с оптического сенсора комьютерной мыши с помощью Arduino / Хабрахабр

    Рекавери («реабилитация» пользователей с отрицательной кармой)
    In Soviet Russia… Apple не удалось зарегистрировать торговую марку для iPad в Роспатенте / Хабрахабр
    Обзор антикварного компьютера фирмы NEXT / Хабрахабр
    Moon+ Reader восстановлен в Google Play / Хабрахабр
    Hack ВУЗа или как я выбирал университет / Хабрахабр
    Skype 4.0 для Linux / Хабрахабр
    Изобретение украинских студентов одно из лучших по версии «TIME» / Хабрахабр
    8 типов сайтов, которые делать не стоит / Хабрахабр
    Загадка A858 / Хабрахабр
    Один крупный банк, доступ ко всем счетам клиента при наличии копии паспорта / Хабрахабр

    Переводы
    Делаем приватный монитор из старого LCD монитора / Хабрахабр
    Принцип цикады и почему он важен для веб-дизайнеров / Хабрахабр
    Принтер из CD-ROM'a / Хабрахабр
    Node.js — раковая опухоль / Хабрахабр
    Если бы плотников нанимали так же, как программистов / Хабрахабр
    Как правильно сортировать контент на основе оценок пользователей / Блог компании Дару-дар (Darudar) / Хабрахабр
    Решение судоку с помощью веб-камеры в реальном времени / Хабрахабр
    20 вещей, которые я должен был знать в 20 лет / Хабрахабр
    Почему я ушел из Google / Хабрахабр
    8 типов сайтов, которые нужно перестать делать / Хабрахабр

    Тьюториалы (здесь делаю топ-20)
    Прекратите скручивать! / Хабрахабр
    Читаем QR код / Хабрахабр
    Офис компании Boomburum / Хабрахабр
    Полупроводниковая электроника / Хабрахабр
    Декодирование JPEG для чайников / Хабрахабр
    Очнитесь, на дворе XXI век / Хабрахабр
    Процессор / Хабрахабр
    Мой опыт восстановления зрения / Хабрахабр
    Прекратите скручивать — 2. О способах крепления кабеля / Хабрахабр
    Почему в WiMax и LTE используют OFDM / Хабрахабр
    Теория относительности в картинках / Хабрахабр
    От песка до процессора / Блог компании Intel / Хабрахабр
    Как работает стилус Galaxy Note / Хабрахабр
    Смешивание текстур ландшафта / Хабрахабр
    Ежедневная работа с Git / Хабрахабр
    Фотографируем гаджеты для обзора или сайта по-быстрому / Хабрахабр
    Молодым программистам на заметку: Как правильно писать «Помоги» / Хабрахабр
    Сборка компьютера с водяным охлаждением / Хабрахабр
    Выводим деньги с PayPal на карту: Инструкция для чайников / Хабрахабр
    Как из болота вытягивать ITшника или об общении в стрессовых ситуациях / Хабрахабр
    Как заставить хлам приносить пользу? / Хабрахабр
    Прошиваем AVR вручную / Хабрахабр
    VirtualBox 3.2: теперь можно запускать MacOS X в виртуальной машине. Под windows и linux / Хабрахабр
    Фильтр Калмана / Хабрахабр
    Вейвлет-сжатие «на пальцах» / Хабрахабр
    Как высечь огонь из воды / Хабрахабр
    Год с Roomba / Хабрахабр
    Поддержка USB в KolibriOS: что внутри? Часть 1: общая схема / Блог компании KolibriOS Project Team / Хабрахабр
    Учим bash-скрипты, пишем Sokoban / Хабрахабр
    Сниффер витой пары из Wi-Fi роутера / Хабрахабр

    Посты хаба "Я пиарюсь" не участвуют в рейтинге. Топ-10 постов этого хаба.
    Деревянная мышь. История проекта / Хабрахабр
    Деревенские заметки / Хабрахабр
    Лекториум записал почти тысячу лекций за год / Хабрахабр
    Удлинение урлов — занятие бессмысленное и беспощадное / Хабрахабр
    Компьютерная фирма: «за кулисами» / Хабрахабр
    Программирование: индустрия обмана / Хабрахабр
    Микросайтинг / Хабрахабр
    Путь Индейца или как моя игра стала featured в apple app store / Хабрахабр
    Прошу помощи (популярная онлайн-игра отключена следователями ГУВД) / Хабрахабр
    Антипрогресс на передовой / Хабрахабр

    Обещал выложить результаты парсинга. В порядок их так и не привёл, времени нет совсем, отдаю как есть, разобраться можно.
    csv файл с числами по постам: docs.google.com/file/d/0B0GZbSyBTVaYelZmTm11dHlDOTg/edit?usp=sharing
    Изначально я не вытащил информацию о хабах и флажках, поэтому она в отдельных файлах:
    хабы: docs.google.com/file/d/0B0GZbSyBTVaYcDVXTHNnVFVMNGM/edit?usp=sharing
    флажки: docs.google.com/file/d/0B0GZbSyBTVaYaVNZODctRmYwRmM/edit?usp=sharing
    Если сделаете из этого всего что-нибудь интересное, пожалуйста, напишите комментарий.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Шаблоны проектирования в адвенчурах: часть первая

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

    «То, что мы называем хаосом — это всего лишь закономерности, которые мы не сумели распознать. То, что мы называем случайностями — это всего лишь закономерности, которые мы не в состоянии расшифровать.»
    — Чак Паланик

    Как насчет абстрактного подхода к разработке адвенчу? Или, хотя бы, для загадок в адвенчурах — это может оказаться полезным!


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

    Объект или задача (обычно) не достижимы сиюминутно.

    При попытке решить задачу или получить нужный предмет объясняется почему невозможно сделать это сейчас: учитель-нинзя живет в Японии, а вы в Америке; неизвестно, кто купил ядерное оружие; перед башней, где заключена девушка, растет высокий лес; у парня со шляпой есть огромная собака…

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

    Загадки

    Наиболее простое представление пазла выглядит следующим образом:

    Проблема -> Решение

    Большинство моих примеров взято из первой части острова Обезьян. Так что, вы еще не играли в эту игру, то берегитесь спойлеров. (напомню, что игра обе части классической игры, также как и Broken Sword 1 и 2, совсем недавно появились перерисованные в App Store: первая и вторая. Горячо рекомендую!)

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

    Мы всего лишь хотим получить приблизительную, сырую идею того, что мы собираемся формализовать.

    Проблема: Страж
    Решение: Временное

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

    Проблема: Страж (локации)
    Решение: Временное

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

    Проблемы

    Проблемы, естественно, могут немного выйти за описанные рамки.

    Страж (Guardian)
    Есть что-то мешающее вас выполнить нужные действия. Этим чем-то может быть препятствие на локации, может быть охраняемая вещь, или не игровой персонаж (NPC).

    Типичный пример: тролль, охраняющий мост.

    Нетипичный пример: Неприятный запах изо рта NPC — и вы не хотите говорить с ним из-за плохого дыхания


    пер. Broken Sword 2: необходимо обезвредить собаку, прежде, чем пройти дальше

    Требуется нечто (Want FOO)
    Ваш персонаж хочет нечто или ему что-то нужно, но он не может непосредственно получить требуемое. Это может быть знания, деньги, тренировка,…

    Типичный пример: меч стоит 300 золотых монет.

    Нужен ключ (Key Request)
    Для последующих действий персонажу требуется конкретная вещь. Это может быть пароль, принадлежность к конкретной группе, необходимость носить определенную одежду,…

    Типичный пример: закрытая дверь, требующая ключ.

    Временный предмет (Temporal Item)
    Предмет, который вам необходим исчезает до того, как вы можете его использовать. К примеру, вам необходим золотой ключ на рынке воров — но его постоянно крадут, когда вы подходите к двери или вам нужно перенести кислоту, но она постоянно растворяет контейнер.

    Типичный пример: лед, тающий у вас в кармане.

    Нечто спрятанное (Hidden FOO)
    Это ситуация о которой игрок может и не догадываться, потенциально это очень тяжелая задача. Например, это может быть предметом, направление или NPC, который необходим игроку, но где-то спрятан. Напильник в пироге, лесной домик на ветвях дерева, секретный проход, давно пропавший мастер, у которого необходимо получить знания… Вам может понадобится микроскоп, телескоп или нечто другое, что поможет увидеть спрятанные предметы, или необходимо просто догадаться, о наличии спрятанной вещи/пути.

    Типичный пример: напильник в пироге.

    Что-то не достижимо (FOO out of reach)
    Вы можете видеть, чувствовать запах, слышать, видеть доказательства или слухи о чем-то, но не можете физически получить это. Этот паттерн хорошо соотносится с «требуется нечто». Возможно, предмет находится слишком высоко или вы физически не можете дотронуться до него. Допустим это мышь или парашют на дереве, или сундук сокровищ под водой, обезьяна с золотым кольцом, заброшенный город, остров, Луна.

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

    В ловушке (Trapped)
    Ваш персонаж попал в ловушку и необходимо освободить его, например, заперт в комнате, с зацементированными ногами и тонет в воде, думаю, вы легко сможете придумать вариации на эту тему.

    Типичный пример: брошен в тюрьму.

    Приближающаяся опасность (Approaching Danger)
    Если вы остаетесь там где находитесь сейчас и ничего не сделаете, то вы погибнете (или с вами случится нечто страшное). Допустим, вы под водой и скоро задохнетесь, попали в заварушку с бандой байкеров, полиция гонится за вами, злой инопланетянин напротив вас, земля трескается под персонажем, бомба вот-вот взорвется…

    Типичный пример: сломанный меч — встреча с ассасином (пер. имеется ввиду первый Сломанный Меч, где вам необходимо быстро принять решение, также подобная ситуация есть во второй части, где необходимо быстро улизнуть от Гвидо и Жердочки/Флэпа), остров обезьян — тонущий Гайбраш (пер. первая часть серии, Гайбраша скинули с пирса с зацементированными ногами).


    пер. Гайбраш под водой! Нужно срочно что-то сделать!

    Решения

    Проблема может иметь более одного решения или для решение необходимо собрать воедино несколько кусков.

    Новое применение предмета (New Item Perception)
    Предмет может быть понят в новом для себя свете. Например, кастрюля может стать шлемом, летучая мышь может выступать в роли бумеранга. Вещь может выступать в роли того, что может вы можете самостоятельно представить или стать тем, что персонаж мог бы представить самостоятельно, имея определенный набор знаний и навыков. Примерная последовательность действий должна выглядеть следующем образом: необходимо посмотреть на летучую мышь, затем персонаж может сказать нечто подобное “Эй, а она чем-то похожа на бумеранг”, затем в игре явно изменится название предмета на мышеранг и вы сможете использовать предмет как бумеранг.

    Типичный пример: вода в роли зеркала, нож для бумаги как отмычка.

    Комбинирование предметов (Combine Items)
    Вам необходимо скомбинировать, обычно, два предмета из инвенторя для того, что бы получить более полезную вещь. Из яда и мяса можно получить «отравленное мясо», из куска волос и клея — имитацию сгоревших волос, золотая краска и игрушечный значок — значек полицейского…

    Типичный пример: Яд и мясо — «отравленное мясо».

    Метод тыка (Trial and Error)
    В целом, это решение можно не использовать, но при его добавлении времяпрепровождение может стать чуть более забавным. Как корректно сделать предложение племени холмов? Как каждая машина должна быть отрегулирована или совмещена с остальными? В каком порядке три рычага должны быть нажаты? Как правильно выстроить линию беседы?

    Типичный пример: потянуть три рычага в правильном порядке для открытия двери.

    Очевидное использование предмета (Obvious Item Use)
    Непосредственное использование предмета на каком-то другом объекте, использование вещи по ее конкретному назначению. Применить ключа к двери, отдать рыбу голодному троллю, передать деньги продавцу товара.

    Типичный пример: Дать денег продавцу в общем на товар.

    Изменение состояния предмета (Change Item State)
    Это решение очень близко к «очевидному использованию предмета», но тут мы специфицируем предметы, которые могут перейти в другое состояние. Например, разбить стакан для получения режущей поверхности, сжечь дрова для получения древесного угля, приготовить сырое мясо крысы, открыть коробку и посмотреть что внутри…

    Типичный пример: съесть пирог для получения напильника. Открыть и осмотреть сумочку.

    Временный (Temporal)
    Внимание, это решение может быть действительно крайне сложным! Оно подразумевает, что персонаж должен совершинть определенное действие в определенное время — зайти на кухню, когда повар не стоит в двери, принести девственницу в жертву при полной Луне, плюнуть, когда ветер дует вам в лицо, кинуть бомбу, когда газ улетучился… Во всех остальных ситуация аналогичное действие не будет иметь эффекта.

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


    пер. Знаменитая загадка с козлом

    Обезьяна видит, обезьяна делает (Monkey See Monkey Do)
    Это достаточно общее понятние — вы можете увидеть, как NPC произносить пароль, затем вы следуете его примеру, произнося аналогичное кодовое слово. Например, также, вы можете заметить, как он вводит какую-то комбинацию и использовать ее в дальнейшем или физически проследовать за ним, видя, как он куда-то направляется.

    Типичный пример: последовать за NPC в секретное место, например, сокровищницу.

    Повторение (Repitition)
    Совершать одно и тоже действие больше одного раза. При первом повторении, действие может не возыметь эффект, но можно добиться успеха повторяя его больше одного раза. Например, стук в деревянную дверь может ни к чему не привести при первой попытке, при повторении вам уже могут открыть дверь. Вы можете спросить у NPC о чем-нибудь дважды, для того, чтобы показать свою заинтересованы в предмете разговора. Такие решения могут быть достаточно сложными.

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

    Пространственный (Spatial)
    Такое решение может быть более сложным, чем «временный». Действие может увенчаться успехом только если персонаж находится в определенном месте. Например, прячется от патруля, находясь в тени, сбивает яблоко, находясь на возвышенности, стоит за человеком, сталкивая его в карьер…

    Типичный пример: спрятаться в тени.

    Приманка (Bait Item Use)
    Понятие отличное от очевидного использования предмета. С обычным применением вещи вы забрасываем, ждем и подсекаем рыбу. С наживкой мы только закидываем удочку, как рыба сама хватает ее и прыгает к вам на крючек. По сути, вы «приманиваете» реку. Приманка позволяет косвенно решить проблему — пытаемся использовать приманку для того, чтобы с ней что-то провзаимодействовало, в надежде на то, что это поможет решить проблему. Например, бросить бешеного бурундука в повара, таким образом вы сможете стащить его рабочую одежду, положить сыр в мышеловку, поставить очаровательную красотку около дороги, чтобы отвлечь внимание вышибалы.

    Типичный пример: сыр в мышеловке, чтобы поймать мышь.

    Знания из реального мира (Real World Knowledge)

    Решение требует знаний некоторых аспектов реального мира. Конечно, это решение включает в себя практически любой пазл, но хочется выделить именно те ситуации, где это действительно критично. Например, это может быть важным при составлении химического соединение пер. например, в Киандии 2: рука судьбы. Также, могут встретиться загадки, где необходимо использовать магнитом для перемещения металических объектов, знать что сильный магнит поможет стереть кассету, что соль отпугивает зло…

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

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


    Интересна ли тема загадок в адвенчурах?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 204 человека. Воздержалось 38 человек.


    Да



    Нет


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Nokia Lumia 1020: наглядные преимущества в видении Цзин Чжан

    Английский дизайнер с китайскими корнями Цзин Чжан (Jing Zhang) создала удивительную инфографику для Nokia Lumia 1020. Эта работа стала продолжением ее популярной серии «Воображаемая фабрика» (Imaginary Factory), рассказывающей о том, как устроены различные предметы. Под катом вы сможете узнать больше о творчестве дизайнера — и, конечно, о 41 преимуществе нашего нового смартфона с 41-мегапиксельной камерой.

    image

    image
    (кликабельно)

    Цзин Чжан работает в области иллюстраций, типографики и дизайна последние пять лет. Она обосновалась в Лондоне в 2007 году и сначала планировала строить карьеру в области дизайна одежды. Но экономический спад 2008 года смешал все — и ей пришлось заняться графическим дизайном на неоплачиваемой стажировке в небольшой компании. В это непростое время журнал Computer Arts получил молодому дизайнеру работу над одной из обложек. Для недавней выпускницы это стало, по ее словам, скорее даром богов, чем работой. Плюс такое предложение усилило намерение Чжан стать иллюстратором — чем она сейчас и занимается.

    На создание коллекции Imaginary Factory ее вдохновили воспоминания детства — серия игрушек Polly Pocket. Легко умещающийся в карман футляр в открытом состоянии превращался в кукольный домик, внутри которого «жили» несколько маленьких персонажей серии. Юную Чжан завораживал этот миниатюрный мир, который позднее нашел отражение и в других ее работах, например типографике Resort Type.

    image
    Многие проекты Чжан посвящены различным технологиям. В отражении внутренней работы гаджетов ей особенно интересно находить оптимальное сочетание фактов и фантазии. Вымышленные технические детали должны опираться на некую реальную основу, при этом важно не переборщить, чтобы инфографика не превратилась в техническое руководство. Как говорит Чжан, ей очень интересно сначала понять, как устроен предмет, а затем трансформировать это в наглядную фантазийную работу. Итоговая картинка призвана стать шуткой, понятной для всех.

    image

    При работе над инфографикой, посвященной Nokia Lumia 1020, Чжан использовала Cinema 4D для создания трехмерной пространственной среды. Когда перспектива и угол обзора были выставлены, доработка изображения продолжилась в Adobe Illustrator. Дизайнер считает, что признак хорошей инфографики — это удачное сочетание креативности и информационной наполненности. Правильно подобранное количество иллюстраций призвано помочь легче воспринимать сложные данные.
    Чжан очень любит фотографию, и ей нравятся те возможности, которые открывает Lumia 1020 для ее единомышленников. Из 41 преимущества нашего камерофона лично для себя она особенно выделяет эти пять:
    1. Возможность рекадрировать изображения.
    2. 41-мегапиксельный сенсор.
    3. Шесть линз, помогающих создать действительно четкие изображения.
    4. Двойной захват изображения, который сохраняет фото в нескольких разрешениях.
    5. Удобная настройка значения экспозиции для регулировки яркости изображения.

    А что вы думаете о Lumia 1020?

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    В попытке заглянуть за пределы своего ВУЗа или еще одно размышление об учебном процессе

    Этот пост попытка разобраться в жизни за пределами стен моей альма-матер. Волею судеб и своею собственной попал я на факультет прикладной информатики, которых в СНГ много. Все факультеты и кафедры на дне открытых дверей это сосредоточие добра и прогресса на дне открытых дверей, а их жизнь после дня открытых дверей все же несколько отличается от картины на Дне открытых дверей. Именно так получилось и в моем случае. Нельзя сказать что факультет у меня совсем дыра и сосредоточие зла: есть там и предметы интересные, бывают интересные конференции и т.д. Я заметил некоторые проблемы в работе своего факультета, но какяа организация не имеет проблем в своей работе? Мне же интересно насколько описанные ниже проблемы проедставлены в других ВУЗах:

    • Раз информатика прикладная, то и фундаментальным вещам будем уделять внимания много меньше чем прикладным. В чем это выражается? Например в следующем принципе: зачем нам вся эта возня с консольными приложениями?

      У нас нет времени возиться с самим языком программирования, а поэтому сразу будем делать графические приложения на Delphi и неважно, что большинство учащихся конструкции типа for/while составляют с трудом. Итог я наглядно наблюдал на втором курсе в группе: идут уже разделы информатики, которые предполагают знание основных алгоритмических конструкций и конструкций, используемого языка, а большинство так и не могло читать нормально сообщения компилятора об ошибках.

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

    • Математика, даваяемая в рамках маткурсов и используемая в рамках прикладных предметов это две большие разницы. Некоторые разделы матанализа, которые используют «прикладные» предметы не были совершенно освещены в рамках курса матанализа. И речь идет, например, о рядах, элементах операционного счисленяи и т.д., то есть вобщем-то штатных темах матанализа, а не о самых его последних достижениях.

    • Очень сильная абстрактность математического блока предметов. Да нам дают математическую теорию, нам дают решать примеры, сильно привязанные к этой теории, но прикладные и часто «неудобные» для прямого применения теории случаи мы не разбираем и не видим, пока они не возникнут в курсовой или дипломе. Очень хорошо это показал курс по математической статистике и анализу данных. Да нам прочли определенные разделы статистики и анализа данных: тестирование гипотез, снижение размерности данных, кластеризацию и т.д. Однако эти методы читались разрозненно и сам курс не давал какой-то внятной картины, а что с нми всеми делать?

      Это при том что сама наша область приложений позволяет взять множество задач для того, чтобы вокруг них сформулировать проблему для учебного исследования и поэтапно его развивая вводить необходимые разделы статистики. У нас вместо этого пытались просто нагрузить мощным пластом теории, который давали так: например в факторном анализе, используют собственные значения матриц, а поэтому на лекции нам рассказали о ней в течении 15 минут, которые не включили в себя никаких наглядных образов для понимания или объяснения на пальцах, а вообще что это? Дали формальные определения и пример матрицы 2х2 для расчета собственных значений. Всем все стало «понятно». Да но считается, что эта тема нам известна!

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

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

    • Верстка веб-страниц таблицами --последнее достижение веб-дизайна! У нас преподавание веб-технологий тормознуло именно на этом уровне и более того преподаватели (а их целых три: два старшего поколения и один молодой ) считают что все нормально. Правда в частной беседе выяснилось что не все, но студенты же слабые, а поэтому зачем им какие-то там MVC давать и прочее. Сходный зоопарк мамонтов можно наблюдать так или иначе и в других дисциплинах, хотя рядом могут быть и весьма современные вещи.

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

    P.S. Есть такая вероятность что и мне придется встать по ту сторону кафедры и приянть участи в педагогическом процессе, а потому хотелось бы понять: а что же творится?

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Русские привилегии на счетные машины с 1880 по 1895 гг

    image

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

    Привилегия, выданная из Департамента Торговли и Мануфактур в 1881 г. губернскому секретарю Николаю Компанейскому на двойные счетыimage
    image
    image
    image
    image


    Привилегия, выданная из Департамента Торговли и Мануфактур в 1881 г. военному инженеру капитану Юрию Дьякову на нового рода счетыimage
    image
    image
    image
    image
    image
    image


    Привилегия, выданная из Департамента Торговли и Мануфактур в 1891 г. иностранцам Павлу Ильгену и Павлу Е. Кюрстену на контрольное приспособление для счетных приборовimage
    image
    image


    Привилегия, выданная из Департамента Торговли и Мануфактур в 1893 г. дворянину Ивану Орлину на автоматические винтовые счетыimage
    image
    image
    image
    image
    image
    image
    image


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


    Привилегия, выданная из Департамента Торговли и Мануфактур в 1895 г. иностранцу Эмилю Шоллеру на школьный арифметический приборimage
    image
    image
    image


    Привилегия, выданная из Департамента Торговли и Мануфактур в 1893 г. межевому инженеру надворному советнику Константину Гуцевичу на вычислительный прибор: не обнаружена.

    P.S. О грустных мыслях, на которые меня натолкнуло копирование данного материала в Российской Государственной библиотеке, можно прочитать в этом посте (выкладывается одновременно с текущим).

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Копировать произведения, находящиеся в общественном достоянии? Национальная индейская изба вам в помощь

    image

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

    Наблюдения из собственной жизни.

    Около пятнадцати лет посещаю Российскую Государственную библиотеку (бывш. Ленинку). В течение названного некороткого периода наблюдал, как изменялся порядок копирования материалов в ней. В какую сторону, судите сами: трагикомедия в семи актах из жизни квалифицированного российского читателя прилагается. Хронологию не расписываю в силу того, что боюсь напутать, однако за общую правдивость ручаюсь.

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

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

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

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

    Несмотря на сравнительную дороговизну, это был расцвет научной деятельности. За совершенно ту же цену, что на улице, можно было получить копию необходимого в научной деятельности материала. Поскольку многие копировали не отдельные страницы, а целые книги, от клиентов (профессоров, аспирантов, студентов) не было отбою: у ксероксов всегда собиралась очередь. Выполнения заказа приходилось ждать уже меньше: максимум час-полтора, – а при отсутствии очереди он выполнялся в минуты.

    Акт 3-й. Пунктов ксерокопирования стало больше. С одной стороны, замечательно – очереди испарились совершенно, – однако цены на ксерокопии поползли вверх. Сканировать страницу в Ленинке стало отчего-то раза в полтора дороже, чем в любом уличном заведении. Вероятно, в виде налога на культуру, по принципу: если ты такой умный, плати.

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

    Одна беда: на всех читателей Российской Государственной библиотеки приходился единственный сканер. Учитывая платный характер услуги, немного странно, не правда ли? Опять приходилось отстаивать в очередях, а иногда переносить сканирование на следующий день. Ну, читателю не привыкать, какие проблемы.

    Акт 4-й. В пунктах ксерокопирования установили дифференцированные цены, в зависимости от года издания книги. Понятное дело: отксерить книгу 1950 г. – одни трудозатраты, а того же объема книгу 1850 г. – совсем-совсем другие.

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

    Акт 5-й. Счастье продолжалось недолго: гражданское законодательство в части авторского права обновилось.

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

    Имела ли Ленинка на это право, большой вопрос. Насколько я понимаю, сканировать для личных целей новый Гражданский кодекс не возбраняет. Одно дело – сканирование материала, другое – его использование: если я заблуждаюсь, пусть юристы меня поправят. В любом случае обсуждать юридические коллизии с работниками компьютерного отдела не имело смысла, потому что они в юридических вопросах были подкованы гораздо хуже читателей.

    «Не положено», – все, что вы могли от них услышать.

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

    Акт 6-й. Пяток коммерческих центров ксерокопирования, полностью покрывавших потребности в копировании материалов читателей Российской Государственной библиотеки, объединили в один репродукционный центр. Думаю, не объединили, а разогнали, взамен организовав аналогичную коммерческую контору под единой крышей, но для читателей это выглядело как объединение.

    Вспоминаю, что перед данной акцией среди «прихожан» распространялась анкета с вопросами, как они относятся к образованию единого репродукционного центра и не желают ли получить вместо него центр релаксации. Я написал что-то вроде: «Против единого центра не возражаю, при условии, что прекратится коммерция на читателях», – к первой части моего пожелания прислушались, а вот второй частью манкировали.

    Как можно было заранее предположить, цены в специализированной ксерокопировальной конторе Ленинки дешевле не стали.

    Акт 7-й. Мы добрались до текущего печального положения.

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

    Отсканировать книгу самому теперь невозможно: этим занимаются штатные «специалисты». Просят 10 руб. за страницу. Таким образом, сканирование тонкой брошюрки в сотню страниц обойдется читателю… считайте сами: 50 разворотов (если повезет и брошюрка стандартного формата) по 10 руб. = аккурат 500 рубликов. Плюс плата за копирование файла на мою флешку. Сколько, вы думаете, стоит скопировать файл на флешку клиента? 20 руб., чтобы вы знали.

    Копировать при помощи собственных технических средств в Ленинке, как и в других библиотеках и архивах, категорически запрещено, кто бы сомневался. Всегда было запрещено.

    Знаете, что я обо все этом думаю? [Пи-пи-пи-пи] – вот что я думаю об этом. По моим представлениям, за 500 руб. (или ненамного дороже) можно не только сканировать, но и качественно распечатать и переплести стостраничную брошюру по требованию.

    Это в Ленинке, которая всегда была на порядок лучше других библиотек и архивов, не только по хранящимся объемам литературы, но и по доступности ее для читателя! Точно вам говорю, в других местах намного хуже. Помнится, несколько лет назад в одном из архивов за скан заурядной страницы у меня попросили тысячу рублей. На изумленный возглас, а не дорого ли заламывает государственная организация, библиотекарь без тени иронии пояснила:
    «Чтобы работать на сканере, требуется очень большая квалификация».

    Алло, никому не требуются специалисты по копированию файлов (20 руб. за скопированный файл) или по работе на сканере (1000 руб. за отсканированную страницу)?

    Пятнадцать лет технического прогресса псу под хвост: пришли к тому, с чего начали – скопировать книгу (находящуюся в общественном достоянии, обращаю ваше внимание!) рядовому читателю не по карману. Мне, во всяком случае. Если какое-то время назад я мог позволить себе самостоятельно за 50 руб. отсканировать брошюру и выложить в общественный доступ, то платить вдесятеро большую сумму, извините, не в состоянии.

    В сравнении с тем, что было десять-пятнадцать лет назад, ныне в Российской Государственной библиотеке запустение: не видно ни седовласых профессоров, ни озабоченных аспирантов, ни румяных студентов – изредка пробежит один-другой, и снова тишь, да гладь, да Божья благодать, только незанятые библиотечные работники снуют туда-сюда. По моим личным наблюдениям, посетителей раз в пять меньше. Разумеется, часть читателей отсеялась в связи с развитием сетевых компьютерных технологий, но многих – ох, многих! – отвадили от посещения библиотеки цены. Ведь в Ленинке по-прежнему полно неоцифрованного материала, которого в Сети не найти. Остается переписывать информацию ручками в школьную тетрадку, совсем как в былые времена. Вход в библиотеку пока бесплатный – не знаю, задумывается ли об этом досадном упущении начальство: платная выдача книг стала бы логичным продолжением проводимой ей политики.

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

    1. Предлагаю оцифровать материалы всех – всех, вы слышите! – библиотек и архивов. Находятся же у государства деньги на всякую [пи-пи-пи-пи], пускай и на культуру отыщутся.
    Все несекретные и не охраняемые авторским правом материалы следует выложить в открытый доступ.

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

    3. Современные книгоиздатели должны передавать цифровые копии своей продукции библиотекам. За непередачу – штраф в размере расходов на сканирование книги.
    Год или два назад подобное требование присутствовало в каком-то законопроекте, однако его завернули под маркой, что могут пострадать правообладатели. Каких-то писателей к протестам привлекли, не помню уже: те опасались, что потеряют деньги, поскольку библиотеки не в состоянии обеспечить сохранность файлов. Смехотворная аргументация: как будто единственным способом сделать цифровую копию книги является кража библиотечного файла, а оцифровать книгу после ее покупки в магазине совершенно невозможно.


    Такие предложения, короче.

    P.S. Если кому интересно: мысль написать данный пост пришла после того, как отдал 350 кровных рубликов за 33 отсканированных странички. Искомые странички выложены на Хабре одновременно с текущим постом (здесь). Вот правильно говорят: ни одно доброе дело не остается безнаказанным. Одни обнародуют информацию, находящуюся в общественном достоянии, другие на вроде бы бесплатной информации нехило зарабатывают, никакого копирайта не требуется. Каждому свое.


    Как вы относитесь к высказанным предложениям?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 627 человек. Воздержалось 172 человека. Источник: habrahabr.ru,
    получено с помощью rss-farm.ru




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



    Автор прав не во всем.



    Полностью с автором солидарен!.. [Пи-пи-пи].

    Мексиканский город поднял собственную сотовую сеть


    Вилья-Талеа-де-Кастро

    Маленький город Вилья-Талеа-де-Кастро (Villa Talea de Castro), с населением около 2500 жителей находится на удалении от густонаселённых районов Мексики и оживлённых автотрасс, поэтому его игнорируют все работающие в стране операторы мобильной связи. Более того, в городе отсутствует даже наземная связь, то есть нет вообще никаких телефонов. Тянуть в горы оптоволокно и устанавливать оборудование ради тысячи клиентов считалось нерентабельным. Например, оператор Telcel обеспечивает связь в городах с более чем 10 тыс. жителей.

    После многих лет ожидания городок Вилья-Талеа-де-Кастро показал пример, что нужно делать в такой ситуации. При помощи нескольких общественных организаций и университетов местные жители подняли антенну на крышу здания, установили радио- и компьютерное оборудование — и зарегистрировали собственного микропровайдера Red Celular de Talea.


    Установка антенны

    Абонентская плата в сети микропровайдера составляет всего 15 песо (1 доллар 20 центов) в месяц. Это в 13 раз меньше, чем базовый тариф Telcel в столице Мехико. За три месяца после открытия сервиса на услуги Red Celular de Talea подписались уже более 600 местных жителей.

    Минута связи по VoIP с США, например, обходится всего в несколько центов. У многих дети эмигрировали в соседнюю Америку, и раньше им приходилось звонить из таксофона по 10 песо за минуту.

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

    Самую большую помощь в оборудовании города сотовой связью сетью оказала некоммерческая организация Rhizomatica. Городские власти получили двухлетний мандат от Федеральной комиссии по связи на «тестирование оборудования» на частоте 900 МГц.



    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Алгоритм генерации судоку

    sudoku250title
    Доброго времени суток!

    Думаю, головоломка Судоку не нуждается в представлении. Многие из нас проводят за её решением достаточно много времени. Например, когда нужно убить время в дороге или просто поворочать мозги, чтобы не сохли. На хабре есть довольно много постов о решении головоломки. Но когда человек решает с десяток, а может и сотню головоломок, то найдётся пытливый ум, который задаст себе вопрос «А как же получается таблица Судоку, имеющая единственное решение? И как можно описать алгоритм для сетки 9x9?».

    Приведённый алгоритм является вполне логичным. Но моей задачей было описание и реализация. Обо всём этом написано под катом.

    Основные правила Судоку
    1. Цифра может появиться только один раз в каждой строчке
    2. Цифра может появиться только один раз в каждом столбике

    3. Цифра может появиться только один раз в каждом районе (Район — меньший квадрат со стороной 3х3, на изображении ниже выделен фиолетовым цветом)



    Шаг 1. Взять за основу базовую сетку

    Сетка должна подчинятся правилам Судоку. Размещаем в первую строку 1 2… 8 9, в строках ниже смещаем на 3 позиции влево, т.е. 4 5… 2 3 и 7 8… 5 6.
    Далее переходя в следующий район по вертикали смещаем на 1 позицию влево предыдущий район.

    В итоге должна получиться вот такая сетка, её я и назову базовой:


    Для реализации создадим класс grid. Заполним его в соответствии с Шагом 1, в котором table — список значений таблицы, метод show — просто наглядный вывод таблицы.

    <code class="python">class grid:
    	def __init__(self,n = 3):
    		"""Generation of the base table"""
    		self.n = n
    		self.table = [[((i*n + i/n + j) % (n*n) + 1) for j in range(n*n)] for i in range(n*n)]
    		print "The base table is ready!"
    
    	def __del__(self):
    		pass
    	
    	def show(self):
    		for i in range(self.n*self.n):
    			print self.table[i]
    </code>

    Шаг 2. Перетасовать сетку

    Есть несколько видов перестановок, выполнив которые таблица Судоку останется в допустимом состоянии.
    К ним относятся:

    • Транспонирование всей таблицы — столбцы становятся строками и наоборот (transposing)


    • Обмен двух строк в пределах одного района (swap_rows_small)
    • Обмен двух столбцов в пределах одного района (swap_colums_small)


    • Обмен двух районов по горизонтали (swap_rows_area)
    • Обмен двух районов по вертикали (swap_colums_area)


    Для каждой из перестановок напишем метод:
    transposing
    <code class="python">	def transposing(self):
    		""" Transposing the whole grid """
    		self.table = map(list, zip(*self.table))
    </code>
    swap_rows_small
    <code class="python">	def swap_rows_small(self):
    		""" Swap the two rows """
    		area = random.randrange(0,self.n,1)
    		line1 = random.randrange(0,self.n,1)
    		#получение случайного района и случайной строки
    		N1 = area*self.n + line1
    		#номер 1 строки для обмена
    
    		line2 = random.randrange(0,self.n,1)
    		while (line1 == line2):
    			line2 = random.randrange(0,self.n,1)
    
    		N2 = area*self.n + line2
    		#номер 2 строки для обмена
    
    		self.table[N1],self.table[N2] = self.table[N2], self.table[N1]
    </code>
    swap_colums_small
    Для обмена столбцов можно поменять строки у транспонированной таблицы:
    <code class="python">	def swap_colums_small(self):
    		grid.transposing(self)
    		grid.swap_rows_small(self)
    		grid.transposing(self)
    </code>
    swap_rows_area
    <code class="python">	def swap_rows_area(self):
    		""" Swap the two area horizon """
    		area1 = random.randrange(0,self.n,1)
    		#получение случайного района
    
    		area2 = random.randrange(0,self.n,1)
    		while (area1 == area2):
    			area2 = random.randrange(0,self.n,1)
    
    		for i in range(0, self.n):
    			N1, N2 = area1*self.n + i, area2*self.n + i
    			self.table[N1], self.table[N2] = self.table[N2], self.table[N1]
    </code>
    swap_colums_area
    <code class="python">	def swap_colums_small(self):
    		grid.transposing(self)
    		grid.swap_rows_area(self)
    		grid.transposing(self)
    </code>
    Может быть есть ещё более сложные преобразования, но, думаю, можно ограничиться этими. Этот каркас инвариантен своей структуре, такие перестановки есть почти тоже самое, что и действия над матрицами относительно определителя или вращение Кубика Рубика.

    Теперь, для того чтобы получить случайную комбинацию, достаточно запустить в случайном порядке функции перемешивания. Так и поступим, amt — количество перемешиваний:
    <code class="python">	def mix(self,amt = 10):
    		mix_func = ['self.transposing()', 
    					'self.swap_rows_small()', 
    					'self.swap_colums_small()', 
    					'self.swap_rows_area()', 
    					'self.swap_colums_area()']
    		for i in xrange(1, amt):
    			id_func = random.randrange(0,len(mix_func),1)
    			eval(mix_func[id_func])
    </code>
    Пример 10 итераций перемешивания
    <code class="python">base
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    [4, 5, 6, 7, 8, 9, 1, 2, 3]
    [7, 8, 9, 1, 2, 3, 4, 5, 6]
    [2, 3, 4, 5, 6, 7, 8, 9, 1]
    [5, 6, 7, 8, 9, 1, 2, 3, 4]
    [8, 9, 1, 2, 3, 4, 5, 6, 7]
    [3, 4, 5, 6, 7, 8, 9, 1, 2]
    [6, 7, 8, 9, 1, 2, 3, 4, 5]
    [9, 1, 2, 3, 4, 5, 6, 7, 8]
    
    swap_colums_area
    [7, 8, 9, 4, 5, 6, 1, 2, 3]
    [1, 2, 3, 7, 8, 9, 4, 5, 6]
    [4, 5, 6, 1, 2, 3, 7, 8, 9]
    [8, 9, 1, 5, 6, 7, 2, 3, 4]
    [2, 3, 4, 8, 9, 1, 5, 6, 7]
    [5, 6, 7, 2, 3, 4, 8, 9, 1]
    [9, 1, 2, 6, 7, 8, 3, 4, 5]
    [3, 4, 5, 9, 1, 2, 6, 7, 8]
    [6, 7, 8, 3, 4, 5, 9, 1, 2]
    
    swap_colums_small
    [7, 8, 9, 4, 5, 6, 2, 1, 3]
    [1, 2, 3, 7, 8, 9, 5, 4, 6]
    [4, 5, 6, 1, 2, 3, 8, 7, 9]
    [8, 9, 1, 5, 6, 7, 3, 2, 4]
    [2, 3, 4, 8, 9, 1, 6, 5, 7]
    [5, 6, 7, 2, 3, 4, 9, 8, 1]
    [9, 1, 2, 6, 7, 8, 4, 3, 5]
    [3, 4, 5, 9, 1, 2, 7, 6, 8]
    [6, 7, 8, 3, 4, 5, 1, 9, 2]
    
    swap_colums_small
    [7, 8, 9, 4, 5, 6, 1, 2, 3]
    [1, 2, 3, 7, 8, 9, 4, 5, 6]
    [4, 5, 6, 1, 2, 3, 7, 8, 9]
    [8, 9, 1, 5, 6, 7, 2, 3, 4]
    [2, 3, 4, 8, 9, 1, 5, 6, 7]
    [5, 6, 7, 2, 3, 4, 8, 9, 1]
    [9, 1, 2, 6, 7, 8, 3, 4, 5]
    [3, 4, 5, 9, 1, 2, 6, 7, 8]
    [6, 7, 8, 3, 4, 5, 9, 1, 2]
    
    transposing
    [7, 1, 4, 8, 2, 5, 9, 3, 6]
    [8, 2, 5, 9, 3, 6, 1, 4, 7]
    [9, 3, 6, 1, 4, 7, 2, 5, 8]
    [4, 7, 1, 5, 8, 2, 6, 9, 3]
    [5, 8, 2, 6, 9, 3, 7, 1, 4]
    [6, 9, 3, 7, 1, 4, 8, 2, 5]
    [1, 4, 7, 2, 5, 8, 3, 6, 9]
    [2, 5, 8, 3, 6, 9, 4, 7, 1]
    [3, 6, 9, 4, 7, 1, 5, 8, 2]
    
    swap_colums_small
    [7, 1, 4, 8, 2, 5, 6, 3, 9]
    [8, 2, 5, 9, 3, 6, 7, 4, 1]
    [9, 3, 6, 1, 4, 7, 8, 5, 2]
    [4, 7, 1, 5, 8, 2, 3, 9, 6]
    [5, 8, 2, 6, 9, 3, 4, 1, 7]
    [6, 9, 3, 7, 1, 4, 5, 2, 8]
    [1, 4, 7, 2, 5, 8, 9, 6, 3]
    [2, 5, 8, 3, 6, 9, 1, 7, 4]
    [3, 6, 9, 4, 7, 1, 2, 8, 5]
    
    swap_rows_small
    [7, 1, 4, 8, 2, 5, 6, 3, 9]
    [8, 2, 5, 9, 3, 6, 7, 4, 1]
    [9, 3, 6, 1, 4, 7, 8, 5, 2]
    [5, 8, 2, 6, 9, 3, 4, 1, 7]
    [4, 7, 1, 5, 8, 2, 3, 9, 6]
    [6, 9, 3, 7, 1, 4, 5, 2, 8]
    [1, 4, 7, 2, 5, 8, 9, 6, 3]
    [2, 5, 8, 3, 6, 9, 1, 7, 4]
    [3, 6, 9, 4, 7, 1, 2, 8, 5]
    
    swap_rows_small
    [7, 1, 4, 8, 2, 5, 6, 3, 9]
    [8, 2, 5, 9, 3, 6, 7, 4, 1]
    [9, 3, 6, 1, 4, 7, 8, 5, 2]
    [5, 8, 2, 6, 9, 3, 4, 1, 7]
    [4, 7, 1, 5, 8, 2, 3, 9, 6]
    [6, 9, 3, 7, 1, 4, 5, 2, 8]
    [2, 5, 8, 3, 6, 9, 1, 7, 4]
    [1, 4, 7, 2, 5, 8, 9, 6, 3]
    [3, 6, 9, 4, 7, 1, 2, 8, 5]
    
    swap_rows_area
    [7, 1, 4, 8, 2, 5, 6, 3, 9]
    [8, 2, 5, 9, 3, 6, 7, 4, 1]
    [9, 3, 6, 1, 4, 7, 8, 5, 2]
    [2, 5, 8, 3, 6, 9, 1, 7, 4]
    [1, 4, 7, 2, 5, 8, 9, 6, 3]
    [3, 6, 9, 4, 7, 1, 2, 8, 5]
    [5, 8, 2, 6, 9, 3, 4, 1, 7]
    [4, 7, 1, 5, 8, 2, 3, 9, 6]
    [6, 9, 3, 7, 1, 4, 5, 2, 8]
    
    swap_colums_small
    [7, 1, 4, 8, 2, 5, 6, 9, 3]
    [8, 2, 5, 9, 3, 6, 7, 1, 4]
    [9, 3, 6, 1, 4, 7, 8, 2, 5]
    [2, 5, 8, 3, 6, 9, 1, 4, 7]
    [1, 4, 7, 2, 5, 8, 9, 3, 6]
    [3, 6, 9, 4, 7, 1, 2, 5, 8]
    [5, 8, 2, 6, 9, 3, 4, 7, 1]
    [4, 7, 1, 5, 8, 2, 3, 6, 9]
    [6, 9, 3, 7, 1, 4, 5, 8, 2]
    </code>

    Шаг 3. Удаление клеток

    После полученного решения нам необходимо получить задачу (именно в такой последовательности мы можем гарантировать однозначность решения). И это самая сложная часть. Какое количество можно убрать, чтобы гарантировать однозначность решения? Это один из важных факторов, от которого зависит сложность Судоку. Всего в Судоку 81 клетка, обычно считают лёгким когда на поле есть 30-35 «подсказок», средним — 25-30, и сложным — 20-25. Это данные большого набора реальных примеров. Нет никаких законов для сложности. Можно сделать 30-клеточный неразрешимый вариант и 22 клеточный «лёгкий».

    • Случайный подход — можно попробовать выкинуть 50-60 клеток наугад, но где вероятность что Судоку можно будет решить? Например, если заполнены 3 строки ( = 27 клеток)
    • Случайно с простым ограничением — для примера можно взять некое число N в качестве предела, так что N строк и столбцов могут быть пустыми. Принимая N = 0 — для лёгких уровней, N=1 — средний, N=2 — сложный
    Итак, приступим к вычёркиванию ячеек (все варианты равнозначны, поэтому у нас 81 ячейка, которую можно вычеркнуть, поэтому проверим все перебором):

    1. Выбрать случайную ячейку N
    2. Отметить N просмотренной
    3. Удалить N
    4. Посчитать решения. Если оно не единственное, то вернуть N обратно
    На выходе получится самая сложная из возможных вариантов Судоку для данного перемешивания. Переменная difficult оценивает сложность — количество оставшихся элементов.

    <code class="python">
    flook = [[0 for j in range(example.n*example.n)] for i in range(example.n*example.n)]
    iterator = 0
    difficult = example.n ** 4 #Первоначально все элементы на месте
    
    while iterator < example.n ** 4:
    	i,j = random.randrange(0, example.n*example.n ,1), random.randrange(0, example.n*example.n ,1) # Выбираем случайную ячейку
    	if flook[i][j] == 0:	#Если её не смотрели
    		iterator += 1
    		flook[i][j] = 1 	#Посмотрим
    
    		temp = example.table[i][j]	#Сохраним элемент на случай если без него нет решения или их слишком много
    		example.table[i][j] = 0
    		difficult -= 1 #Усложняем, если убрали элемент
    
    		table_solution = []
    		for copy_i in range(0, example.n*example.n):
    			table_solution.append(example.table[copy_i][:]) #Скопируем в отдельный список
    
    		i_solution = 0
    		for solution in solver.solve_sudoku((example.n, example.n), table_solution):
    			i_solution += 1 #Считаем количество решений
    
    		if i_solution != 1: #Если решение не одинственное -- вернуть всё обратно
    			example.table[i][j] = temp
    			difficult += 1  #Облегчаем
    
    example.show()
    print "difficult = ",difficult
    </code>

    sudoku_generator.py
    <code class="python"># coding=utf-8
    import random
    import solver
    
    class grid:
    	def __init__(self,n = 3):
    		""" Generation of the base table """
    		self.n = n
    		self.table = [[ ((i*n + i/n + j) % (n*n) + 1) for j in range(n*n)] for i in range(n*n)]
    		print "The base table is ready!"
    
    	def __del__(self):
    		pass
    	
    	def show(self):
    		for i in range(self.n*self.n):
    			print self.table[i]
    
    	def transposing(self):
    		""" Transposing the whole grid """
    		self.table = map(list, zip(*self.table))
    
    	def swap_rows_small(self):
    		""" Swap the two rows """
    		area = random.randrange(0,self.n,1)
    		line1 = random.randrange(0,self.n,1)
    		#получение случайного района и случайной строки
    		N1 = area*self.n + line1
    		#номер 1 строки для обмена
    
    		line2 = random.randrange(0,self.n,1)
    		#случайная строка, но не та же самая
    		while (line1 == line2):
    			line2 = random.randrange(0,self.n,1)
    
    		N2 = area*self.n + line2
    		#номер 2 строки для обмена
    
    		self.table[N1],self.table[N2] = self.table[N2], self.table[N1]
    
    
    	def swap_colums_small(self):
    		grid.transposing(self)
    		grid.swap_rows_small(self)
    		grid.transposing(self)
    
    
    	def swap_rows_area(self):
    		""" Swap the two area horizon """
    		area1 = random.randrange(0,self.n,1)
    		#получение случайного района
    
    		area2 = random.randrange(0,self.n,1)
    		#ещё район, но не такой же самый
    		while (area1 == area2):
    			area2 = random.randrange(0,self.n,1)
    
    		for i in range(0, self.n):
    			N1, N2 = area1*self.n + i, area2*self.n + i
    			self.table[N1], self.table[N2] = self.table[N2], self.table[N1]
    
    
    	def swap_colums_area(self):
    		grid.transposing(self)
    		grid.swap_rows_area(self)
    		grid.transposing(self)
    	
    	def mix(self,amt = 10):
    		mix_func = ['self.transposing()', 
    					'self.swap_rows_small()', 
    					'self.swap_colums_small()', 
    					'self.swap_rows_area()', 
    					'self.swap_colums_area()']
    		for i in xrange(1, amt):
    			id_func = random.randrange(0,len(mix_func),1)
    			eval(mix_func[id_func])
    
    example = grid()
    example.mix()
    
    flook = [[0 for j in range(example.n*example.n)] for i in range(example.n*example.n)]
    iterator = 0
    difficult = example.n ** 4 #Первоначально все элементы на месте
    
    example.show() 
    print "---------------------------"
    
    while iterator < example.n ** 4:
    	i,j = random.randrange(0, example.n*example.n ,1), random.randrange(0, example.n*example.n ,1) # Выбираем случайную ячейку
    	if flook[i][j] == 0:	#Если её не смотрели
    		iterator += 1
    		flook[i][j] = 1 	#Посмотрим
    
    		temp = example.table[i][j]	#Сохраним элемент на случай если без него нет решения или их слишком много
    		example.table[i][j] = 0
    		difficult -= 1 #Усложняем если убрали элемент
    
    		table_solution = []
    		for copy_i in range(0, example.n*example.n):
    			table_solution.append(example.table[copy_i][:]) #Скопируем в отдельный список
    
    		i_solution = 0
    		for solution in solver.solve_sudoku((example.n, example.n), table_solution):
    			i_solution += 1 #Считаем количество решений
    
    		if i_solution != 1: #Если решение не одинственное вернуть всё обратно
    			example.table[i][j] = temp
    			difficult += 1 # Облегчаем
    
    example.show()
    print "difficult = ",difficult
    </code>

    solver.py
    <code class="python">#!/usr/bin/env python3
    
    # Author: Ali Assaf <ali.assaf.mail@gmail.com>
    # Copyright: © 2010 Ali Assaf
    # License: GNU General Public License <http://www.gnu.org/licenses/>
    
    from itertools import product
    
    def solve_sudoku(size, grid):
        """ An efficient Sudoku solver using Algorithm X.
    
        >>> grid = [
        ...     [5, 3, 0, 0, 7, 0, 0, 0, 0],
        ...     [6, 0, 0, 1, 9, 5, 0, 0, 0],
        ...     [0, 9, 8, 0, 0, 0, 0, 6, 0],
        ...     [8, 0, 0, 0, 6, 0, 0, 0, 3],
        ...     [4, 0, 0, 8, 0, 3, 0, 0, 1],
        ...     [7, 0, 0, 0, 2, 0, 0, 0, 6],
        ...     [0, 6, 0, 0, 0, 0, 2, 8, 0],
        ...     [0, 0, 0, 4, 1, 9, 0, 0, 5],
        ...     [0, 0, 0, 0, 8, 0, 0, 7, 9]]
        >>> for solution in solve_sudoku((3, 3), grid):
        ...     print(*solution, sep='\\n')
        [5, 3, 4, 6, 7, 8, 9, 1, 2]
        [6, 7, 2, 1, 9, 5, 3, 4, 8]
        [1, 9, 8, 3, 4, 2, 5, 6, 7]
        [8, 5, 9, 7, 6, 1, 4, 2, 3]
        [4, 2, 6, 8, 5, 3, 7, 9, 1]
        [7, 1, 3, 9, 2, 4, 8, 5, 6]
        [9, 6, 1, 5, 3, 7, 2, 8, 4]
        [2, 8, 7, 4, 1, 9, 6, 3, 5]
        [3, 4, 5, 2, 8, 6, 1, 7, 9]
        """
        R, C = size
        N = R * C
        X = ([("rc", rc) for rc in product(range(N), range(N))] +
             [("rn", rn) for rn in product(range(N), range(1, N + 1))] +
             [("cn", cn) for cn in product(range(N), range(1, N + 1))] +
             [("bn", bn) for bn in product(range(N), range(1, N + 1))])
        Y = dict()
        for r, c, n in product(range(N), range(N), range(1, N + 1)):
            b = (r // R) * R + (c // C) # Box number
            Y[(r, c, n)] = [
                ("rc", (r, c)),
                ("rn", (r, n)),
                ("cn", (c, n)),
                ("bn", (b, n))]
        X, Y = exact_cover(X, Y)
        for i, row in enumerate(grid):
            for j, n in enumerate(row):
                if n:
                    select(X, Y, (i, j, n))
        for solution in solve(X, Y, []):
            for (r, c, n) in solution:
                grid[r][c] = n
            yield grid
    
    def exact_cover(X, Y):
        X = {j: set() for j in X}
        for i, row in Y.items():
            for j in row:
                X[j].add(i)
        return X, Y
    
    def solve(X, Y, solution):
        if not X:
            yield list(solution)
        else:
            c = min(X, key=lambda c: len(X[c]))
            for r in list(X[c]):
                solution.append®
                cols = select(X, Y, r)
                for s in solve(X, Y, solution):
                    yield s
                deselect(X, Y, r, cols)
                solution.pop()
    
    def select(X, Y, r):
        cols = []
        for j in Y[r]:
            for i in X[j]:
                for k in Y[i]:
                    if k != j:
                        X[k].remove(i)
            cols.append(X.pop(j))
        return cols
    
    def deselect(X, Y, r, cols):
        for j in reversed(Y[r]):
            X[j] = cols.pop()
            for i in X[j]:
                for k in Y[i]:
                    if k != j:
                        X[k].add(i)
    
    if __name__ == "__main__":
        import doctest
        doctest.testmod()
    </code>

    Результат работы
    <code class="python">The base table is ready!
    [5, 4, 6, 8, 7, 9, 2, 1, 3]
    [8, 7, 9, 2, 1, 3, 5, 4, 6]
    [2, 1, 3, 5, 4, 6, 8, 7, 9]
    [6, 5, 7, 9, 8, 1, 3, 2, 4]
    [9, 8, 1, 3, 2, 4, 6, 5, 7]
    [3, 2, 4, 6, 5, 7, 9, 8, 1]
    [7, 6, 8, 1, 9, 2, 4, 3, 5]
    [1, 9, 2, 4, 3, 5, 7, 6, 8]
    [4, 3, 5, 7, 6, 8, 1, 9, 2]
    ---------------------------
    [0, 0, 6, 0, 0, 0, 0, 0, 0]
    [8, 7, 0, 0, 1, 0, 0, 0, 6]
    [0, 0, 0, 5, 4, 0, 0, 0, 9]
    [6, 0, 0, 0, 8, 1, 3, 0, 4]
    [0, 0, 0, 3, 0, 0, 0, 5, 0]
    [0, 0, 0, 0, 0, 7, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0, 0]
    [0, 9, 0, 4, 0, 0, 0, 0, 8]
    [0, 0, 5, 0, 6, 0, 1, 0, 0]
    difficult =  22
    </code>

    Скачать в zip

    Я уверен, что есть и более сложные подходы в построении таблицы Судоку. Моя цель была достигнута, получился рабочий алгоритм. Теперь мне не нужно искать новые выпуски, я могу их генерировать :)
    В принципе, здесь был приведён частный случай Судоку 9х9. Но нет ограничений для использования его на 16х16 и 25х25.

    Если у кого есть лучшие предложения — не стесняйтесь оставить комментарий.
    Спасибо за внимание.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Замкнутая экосистема по-русски

    Здравствуй, Хабр!

    Недавно наткнулся в интернете на интересную статью, с точки зрения садоводства, об англичанине, который 53 года назад посадил в банку традесканцию.Он закупорил бутылку и, после полива 40 лет назад, больше не открывал её. Идеи пришла ему из любопытства. И по сей день растение живет, растет и поглощает кислород. Традесканция образовала экосистему: при фотосинтезе образуется кислород, происходит увлажнение воздуха внутри сосуда и выпадает влага, опавшие листья перегнивают, выделяя CO2. Но для фотосинтеза нужен еще и свет, поэтому бутылку нужно постоянно пододвигать к окну и разворачивать, чтобы листья росли равномерно. Я добавил немного электроники для комнатного растения, и вот, что из этого получилось.

    Этап Первый
    Как уже говорилось, в процессе фотосинтеза самое важное это свет. Но не любой!
    image

    Для растений наиболее важным является сине-зеленый и желто-красный. Длины волн соответственно от 400 до 450 мкм и от 600 до 650 мкм. Я пошел в магазин и купил 4 красных, 2 синих и 2 зеленых светодиода (прочитав статью на радиокоте). Далее, расположил их под крышкой банки, закрепив на картонке, и соединил параллельно (на 2 красных 1 синий и 1 зеленый).
    Т. к. светодиоды разных цветов свечения имеют разное напряжение питания, поставил резисторы. imageВ крышке сделал отверстие для проводов и укрепил картонку со светодиодами под крышкой, предварительно просунув провода в дырку. Для большей изоляции от внешнего мира дырку можно заклеить.

    Этап Второй

    Основное, т. е. подсветку, я уже сделал, поэтому перехожу к полезным дополнениям.
    1. Чтобы свет горел только тогда, когда растение находится в тени, нужно добавить фотоэлемент.
    Схема подключения:

    Чтобы сделать горшок совсем умным, подключим к нему Arduino. Analog InPut на схеме — любой аналоговый вход у Arduino. На ШИМ (или PWM) выход повесим светодиоды, яркость свечения которых будет изменяться в зависимости от освещенности фоторезистора. Но для начала выясним, какие значения будет выдавать делитель напряжения.
    Код
    <code class="cpp"> int sensor =0; // подключаем делитель к аналоговому входу Arduino A0 
     void setup() {
       
       Serial.begin(9600);
       
     }
    
     void loop() { 
       Serial.println(analogRead(sensor));
       delay(1000); // Отправляет значения с делителя раз в секунду
     }
    </code>

    В своей схеме я использовал фоторезистор из электронного конструктора ЗНАТОКа. У него теневое сопротивление 120 кОм. Расчет резистора R1 производится по формуле: R
    1=Vin
    *R
    2:Vout
    -R
    2
    (Я надеюсь, все хорошо помнят порядок действий: сначала действия первой степени — умножение и деление, а потом второй — сложение и вычитание). Также, следует помнить, что сопротивление у фоторезистора может изменяться нелинейно.
    Минимальное значение с моего делителя — около 100 (назовём их условными единицами), максимальное — около 755 у.е.
    Зная эти значения можно написать программу для Arduino — контроллера.
    Код
    <code class="cpp"> int sensor = 0; // Потенциометр к А0
     int ledPin = 9; //Светодиоды к выходу 9
     void setup ()
     {
       analogReference(DEFAULT);
       pinMode(ledPin, OUTPUT);
       //Serial.begin(9600); Раскомментируйте эту строку для отображения текущей 
       //освещенности в у.е. в Мониторе Порта.
     }
    
     void loop()
     { 
       int val = analogRead(sensor);
      
       val = constrain(val, 130, 755); //Выставляем значения освещенности.
                                       //Если < 130, то превращаем в 130, если > 755, то выставляем в 755.
       int ledLevel = map(val, 130, 755, 0, 255);  //Превращаем значения освещенности и у.е. 
       //в 8-битные значения для ШИМ.
      
       analogWrite(ledPin, ledLevel);
      
       // Serial.println(analogRead(ledLevel));  Раскомментируйте эту строку для отображения текущей 
       //освещенности в у.е. в Мониторе Порта.
     }
      
    </code>


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

    2. Каким бы Arduino не было умным, его вычислительные возможности здесь излишни. Добавив к делителю стабилитрон и транзистор получим все тоже, что и с процессором, только в меньшем объеме. Схема:

    Стабилитрон D1 — любой мошности на 3.6 В. Транзистор T1 — любой NPN.

    P.S. Смотрелось бы намного лучше, если бы провода не торчали. Сама конструкция будет технологичнее, если на дно банки положить катушку и питать подсветку без проводов (по примеру беспроводной зарядки у телефонов).





    Список источников
    1. Видео уроки по Arduino от Джереми Блума (Jeremy Blum) в переводе Амперки (amperka.ru).

    2. Фитолампа


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    В пятницу 6-го сентября НАСА запускает зонд LADEE к луне для исследования разряжённой атмосферы и изучения частиц пыли

    image

    Космический аппарат LADEE (Lunar Atmosphere and Dust Environment Explorer) после запуска проведёт 5 месяцев в пути к луне, проверяя системы и выходя на требуемую, почти круговую орбиту на высоте около 50 км над поверхностью луны.

    Интересно, что одной из задач миссии является выяснение природы странного свечения которое наблюдали астронавты побывавшие на поверхности луны. Ниже зарисовка свечений и лучей наблюдаемых астронавтами миссий «Аполлонов» во время восходов и закатов солнца на луне.

    image

    После завершения 100-дневной миссии исследования тончайшей атмосферы луны, аппарат изменит свою орбиту на эллиптическую и перейдёт к следующей поставленной перед ним задаче — к испытанию оптической системы связи с большой пропускной способностью (более 600 Мбит/с) Lunar Laser Com Demo (LLCD). С помощью лазера зонд будет отправлять и принимать сигналы с земли. Принцип схожий с тем как передаётся сигнал по оптоволоконному кабелю.

    Запуск запланирован на 6-ое сентября на 18:30 по Киевскому времени (19:30 по Московскому). Запуск будет произведён с космодрома Уоллопс. Космический аппарат уже сейчас находится в носовой части ракеты Минотавр-5.
    image

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Пост]пятница — словарим с Lettered.Me

    image… Хорошая идея, как и волшебники, никогда не опаздывает. Однако, и рано не приходит. Она приходит именно тогда, когда надо. То есть, во время еды.
    Именно так к нам, хабраюзерам dachi304 и jimlet, и пришла идея игры с буквами, словами, языками и мозгами. Пришла приправленная бургерами, Америкой 2350х и котиками хорошим настроением.
    Если история вас заинтриговала, если вы хотите вспомнить все когда-либо прочитанные слова и просто хорошо провести время за игрой с друзьями и прочими хорошими людьми — извольте под кат.
    Итак…
    В начале было Слово.
    И слово было…

    C A K E

    Bake Fake Cake.
    Целых три слова.
    Компания, сидевшая за столом, призадумалась, доедая бургеры.

    На музыкальном аппарате (то бишь Jukebox-e), сошедшем словно с кинолент прошлых лет, было всего 10 букв. Так началась Игра. Первый оффлайн-турнир. Еда была отложена в сторону, блинчики еще не поджарились, а тетрадка неспешно, но верно наполнялась новыми и новыми словами.
    Каждые несколько десятков минут была пауза и фраза в духе «Двадцать шесть — это предел для 10 букв.» После чего Игра продолжалась дальше.
    Пробегавший мимо то туда, то сюда официант часто и заинтересованно посматривал и наврняка хотел присоединиться. Но — служба! Однако теперь он всегда сможет сыграть… Но об этом позже. Угадав все, что можно было угадать за ужин, и загоревшись от идей (и острого соуса) компания дружно двинулась проектировать, кодить, творить!

    image

    Итак, что же мы создали?

    Lettered.Me aka Начитанный Я
    Сервис для Игры.
    Но вы наверное хотите услышать правила?
    О, их не так уж и много.
    Есть 10 случайных букв. На данном этапе — только английские. Из них минимум две гласные. Так интереснее.
    Из этих букв можно составлять слова. Из некоторых слов получается больше, из некоторых меньше — никогда не знаешь.
    Кто составит больше слов — победитель.
    Кто составит меньше — бежит за словарем.
    Играть можно одному, можно в компании.
    Для компании мы предусмотрели сразу несколько режимов:
    • Многострадальный хотсит (в разработке) [олдфажно]
    • Приватная игра (по инвайт-коду)
    • Всепользовательский чемпионат
    Их длительность ограничена 60 минутами, после чего начинается новый раунд, с новыми буквами. В одиночной игре тренировать свою память можно вечно. Кстати, у нас работает сохранение, так что действительно — вечно*.
    *Под условием, что вы — сверхгалактическая энергетическая сущность.
    На данный момент поддержка есть только для английского языка, в процессе — составление адекватного словаря для русского. В теории — поддержка основных европейских языков.

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

    Как оно создавалось?

    Из чего же, из чего же, из чего же
    Сделаны наши мальчишки?

    В основе всего — платформа Java EE, да не простая — а седьмой версии. Для пользовательского интерфейса мы использовали столь популярную нынче AngularJS. Проект крутится на опенсорсном GlassFish 4. В качестве транспортной среды используется наконец-таки стандартизированный для JavaEE механизм веб-сокетов, что, к нашему сожалению, может создать некоторые трудности для пользователей, которые все еще сидят под устаревшими версиями прокси-серверов и браузеров. Обновляйтесь чаще!
    А вот авторизация у нас временно через Persona от корпорации, которая подарила нам браузер-лисичку. Свои функции она выполняет неплохо, но, вероятно, ее мы будем менять.

    А что же дальше?


    Дальше — играйте!

    А мы — пойдем кодить. У нас ведь еще столько всего для вас варится!
    Кроме мобильных приложений мы реализовываем следующее:
    • Прекрасный дизайн приложений
    • Ввод с клавиатуры
    • Альтернативную авторизацию
    • Статистику по играм
    • Профили игроков
    • Интеграцию с соцсетями
    • И все остальное..

    Кстати говоря, наша команда энтузиастов будет рада другим энтузиастам, которые могут захотеть присоединиться к разработке. Программисты, дизайнеры, спонсоры — всем будем рады! Отзывам, комментариям, баг-репортам тоже.

    image

    P.S. автор чудесного фото с котиком — RAMON ESPELT
    P.P.S. А в далеких планах — тру-оффлайновая версия.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Тестирование производительности различных конфигураций Swift OpenStack

    Для тех, кто еще не знаком с объектным хранилищем данный Swift OpenStack, общая информация о структуре и алгоритмах уже была приведена в нашем блоге: habrahabr.ru/company/mirantis_openstack/blog/176195/, habrahabr.ru/company/mirantis_openstack/blog/176455/.

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

    Для того, чтобы увидеть реальное поведение нового свойства, вам потребуются инструменты тестирования, которые смогут достоверно воспроизвести требуемый объем работы. Объектные хранилища данных отличаются от остальных тем, что вместо древесной иерархии для хранения объектов используются невложенные наборы контейнеров и уникальные токены для их нахождения. Итак, для тестирования объектного хранилища данных необходим специальный инструмент — тот, который будет работать с запросами Swift, следуя определенным предписаниям. И тут нам на помощь приходит ssbench и swift-bench — инструменты для тестирования производительности Swift, разработанные SwiftStack.

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

    новых особенностей
    Давайте пробежимся по новым свойствам. Регионы — новый топовый уровень в кольце, группирующий зоны. Более подробно узнать об этой структуре и алгоритме вы можете здесь. Этот уровень поддерживает географическую распределенность кластеров, позволяет класть реплики в многочисленные физические регионы, поддерживая локализацию прокси-сервера (proxy affinity). Проще говоря, прокси-сервер будет в первую очередь использовать локальный регион, а с помощью репликации объекты поступят на остальные регионы.

    Инструментарий
    Тестирование производительности для одной виртуальной машины с установленной Swift-All-In-One (SAIO) проводилось с помощью swift-bench. Этот инструмент является частью самого проекта и позволяет легко собирать необходимую информацию для стандартной конфигурации. Для тестирования составного кластера использовался ssbench, так как он позволяет задать более специфическую нагрузку. ssbench также является open-sourced проектом, созданным SwiftStack, но при этом не является частью проекта Swift.

    Цель
    Главной задачей при использовании swift-bench и ssbench было изучение того, как изменения повлияли на среднее количество запросов в секунду, обрабатываемых объектным хранилищем.

    Структура
    ssbench использует message queue протокол для управления и извлечения информации. Сценарий описывается в файле формата JSON. В зависимости от внесенных конфигураций могут быть проведены разные типы тестирования производительности: нагрузочное, тестирование стабильности и другие.

    Рассмотрим пример сценарий, в котором используется 3 класса файлов tiny, small, medium различающиеся по размеру. «initial_files» задает количество файлов определенного типа. «crud_profile» распределяет количество выполняемых операций для каждого запроса в процентах, учитывая что сумма всех значений в crud_profile — это 100% от общего количества операций в «operation_count». Для примера, «crud_profile»: [3, 4, 2, 2] означает что из всего количества запросов, создание объекта займет 27%, чтение — 36%, обновление и удаление — по 18%. Для максимального количества параллельных клиентов «user_count» будет создано количество контейнеров «container_count», в имени которых будет префикс со строкой из «container_base». При этом «container_concurrency» определяет количество клиентов для создания контейнеров.

    Рассмотрим пример сценария:
    {

    «name»: «Medium test scenario»,

    «sizes»: [{ # описываем типы файлов

    «name»: «tiny»,

    «size_min»: 1000, #диапазон размера объекта в байтах

    «size_max»: 16000

    }, {

    «name»: «small»,

    «size_min»: 100000,

    «size_max»: 200000

    }, {

    «name»: «medium»,

    «size_min»: 1000000,

    «size_max»: 2000000

    }],

    «initial_files»: { #количество объектов заданного типа

    «tiny»: 20,

    «small»: 20,

    «medium»: 2

    },

    «operation_count»: 100, #количество запросов

    «crud_profile»: [3, 4, 2, 2], #распределение запросов среди CREATE, READ, UPDATE и DELETE

    «user_count»: 5,

    «container_base»: «ssbench»,

    «container_count»: 100,

    «container_concurrency»: 10

    }

    ssbench поддерживает авторизацию v 1.0 и v 2.0, что означает, что вы можете его использовать как компонент OpenStack, так и отдельное объектное хранилище.

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

    Далее будет пример отчета ssbench, который был выполнен на виртуальной машине с производительностью:
    RAM: 2GB
    VCPU: 1
    Timing cached reads: 5432.52 MB/sec
    Timing buffered disk reads: 57, 91 MB/sec



    Методология
    Применяя данные инструменты для тестирования производительности, у вас будет возможность оценить разные варианты развертывания объектного хранилища данных Swift и выбрать подходящий именно вам.

    Сравнение колец
    Итак, если вы хотите посмотреть на результаты при разном наборе регионов, количестве девайсов и копий объектов, мы предлагаем такой вариант:
    •Сгрупировать 4 девайса в одном регионе с 4 зонами и 3 репликами
    •Сгрупировать 4 девайса в одном регионе с 2 зонами и 3 репликами
    •Сгрупировать 4 девайса в одном регионе с 1 зоной и 3 репликами
    •Сгрупировать 4 девайса в двух регионах с 4 зонами и 2 репликами

    Мы сравнили показатели для релиза Swift 1.9.0 по мере его формирования с конечным мастером:

    commitnameregionzonePUTSGETSDEL
    dec517e3497df25cff70f99bd6888739d410d771Drop cache after fsync1426.4/s107.832
    13347af64cc976020e343f0fd3767f09e26598deMerge «Improve swift's keystoneauth ACL support»1435.1116.832.9
    151313ba8c6612183f6a733edbcbc311b3360949master swift 1.9.01445.3133.144.2
    151313ba8c6612183f6a733edbcbc311b3360949master swift 1.9.01249.1160.351.3
    151313ba8c6612183f6a733edbcbc311b3360949master swift 1.9.01142.3175.340
    151313ba8c6612183f6a733edbcbc311b3360949master swift 1.9.02454.3109.849.7
    Proxy affinity

    Сравнение количества выполненных запросов при включении и выключении прокси аффинити:
    -Сгруппированы 4 девайса в одном регионе с 4 зонами и 3 репликами

    DisableEnable
    PUTS45,37,2
    GETS133,1160,3
    DEL44.255,2

    — Сгруппированы 4 девайса в одном регионе с 2 зонами и 3 репликами

    DisableEnable
    PUTS49,13,8
    GETS160,3157
    DEL51,357,8
    -Сгруппированы 4 девайса в одном регионе с 1 зоной и 3 репликами

    DisableEnable
    PUTS42,355,3
    GETS175,3160,3
    DEL4055,2

    -Сгруппированы 4 девайса в двух регионах с 4 зоной и 2 репликам
    DisableEnable
    PUTS54,33,4
    GETS109,8136
    DEL49,749

    Как вы заметили, количество обработанных GET запросов возрастает, тогда как PUT падает. Это произошла потому что в настройках прокси для записи были указаны 2 параметра: региона и зона, а значит только 1 девайс будет подходить под это правило. В то время как для чтения был указан только регион, а значит и все девайсы этого региона стали локальными для чтения.

    Пропускная способность
    Другой метод тестирования производительности — сравнение результатов при увеличении количества рабочих процессов в ssbench. В следующем примере каждый worker создает запросы от 12 user:



    Идея такого сценария — постепенное наращивание количества клиентов, до тех пор пока производительность не начнет падать, что означает, что мы достигли предела параллелизации в кластере.

    Другие методы
    Для оценки результатов на составном кластере, мы разделили 9 девайсов на 3 региона. Один мастер собирает данные по всем worker, запущенных на отдельных хостах и создающие запросы от 20 пользователей. Сценарий содержит такие параметры как: работа со 100 контейнеров, 100 файлов размеров 512 MB.
    ID_runr1-01r1-02r1-03r2-01r2-02r2-03r3-01r3-02r3-03
    1masterworkerworker
    2masterworkerworker
    3masterworkerworker
    4masterworkerworker
    5masterworkerworkerworker
    6masterworkerworkerworker
    7masterworkerworkerworkerworker

    Мы использовали такое распределение, что бы собрать информацию по регионам.
    •В первом случае используется только локальный регион
    •Во втором и третьем используется один нелокальный регион
    •В четвертом случае используются два нелокальных региона
    •В случаях 5-7 идет увеличение количества worker

    На шаге 6 мы сталкиваемся с лимитом кластера и производительность начинает падать.

    Заключение
    Данное исследование позволяет нам твердо сказать, что релиз Swift 1.9.0 это рывок на встречу увеличения производительности вашего хранилища.
    Здесь были представлены некоторые методы тестирования производительности, которыми мы пользуемся для исследования и создания продуктов.

    Если вам будет интересно создать свое тестовое окружение, воспользуйтесь следующими ссылками:
    •ssbench GitHub: github.com/swiftstack/ssbench
    •ssbench SwiftStack blog: swiftstack.com/blog/2013/04/18/openstack-summit-benchmarking-swift/
    •Swift 1.9.0 in blog: lists.openstack.org/pipermail/openstack-dev/2013-July/011221.html
    •Swift 1.9.0 info: launchpad.net/swift/+milestone/1.9.0

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Музей Компьютерной Истории

    Привет всем! image

    На прошлых выходных мне посчастливилось побывать в замечательном месте — Музее Компьютерной Истории (Computer History Museum), который находится в городе Маунтин Вью в Калифорнии, США.

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

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

    Музей Компьютерной Истории, так же возможен перевод "Музей Истории Вычислительной Техники", но я предпочитаю вариант номер 1, начинает свою историю в далёком1968 году. Гордон Бэлл в те годы занялся сбором электроники для истории и начал он с компьютера Whirlwind, который я видел и о котором расскажу ниже. Первую выставку «Проект Музей»«Museum Project» провели в 1975 году в лобби компании DEC, которую этот самый Бэлл и возглавлял. В 1978 года «Музей Цифрового Компьютера»«The Digital Computer Museum» переехал в другое лобби DEC в Мальборо, Массачусетс. 1984 году «Компьютерный Музей»«The Computer Museum», переехал в Бостон.

    В конце девяностых артефакты музея были разделены между двумя центрами — Музеем Компьютерной истории здесь, в Кремниевой Долине, и Бостонским музеем науки. С 2003 года Музей получил своё место в бывшем здании Silicon Graphics в Маунтин Вью, где и показывает свои экспонаты сегодня.



    Основная выставка, которая проводится в музее называется «Революция: Первые 2000 лет вычислений» -«Revolution: The First 2000 Years of Computing», которую, собственно, я и посмотрел. Но так же были ещё пару экспозиций, с которых я и начну.

    Основание Кремниевой Долины

    image

    Первая экспозиция, которую я увидел в музее — записи инженеров и учёных, датированные 1957 и 1959 годами. 3 основателя Frairchild SemiconductorJean Hoerni, Gordon Moore и Robert Noyce — описывали инновационные технологии в построении электрических цепей и совершили революцию в истории вычислительной техники.

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

    Раздностная машина Бэббиджа (№2). Babbage Difference engine #2

    Далее по пути встретилось завораживающее представление — работа Счётной машины Бэббиджа. Двое сотрудников музея рассказывали и показывали, как и каким образом работает этот великолепный слаженный механизм.

    На наших глазах вычислялись значения полинома с точностью до 31 знака после запятой:
    image

    image

    image

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

    Экспозиция от Гугл

    Далее по плану шла экспозиция от Гугл Стрит Вью. Был показан основной транспорт, которым снимают окружающие виды. Можно было даже пощупать и посидеть за рулём:
    image

    image

    Революция: первые 2000 лет вычислений

    Далее по плану шла основная выставка музея:
    image

    Но перед самый выставкой, на входе, не знаю почему, стояли 3 экспоната, вряд ли революционные:

    Вычислительная машина для ставок на скачках, Calculating Betting Odds, 1930
    image

    Panasonic Q Game Console, 2001
    image

    На табличке рассказывается о том, что в 2001 году Nintendo, объединившись с Panasonic, выпустили гибрид — игровая консоль и DVD плеер 2 в 1. Но всё вылетело в трубу — было дешевле купить то же самое по отдельности!

    Русский супер-компьютер ЭЛЬБРУС-2, 1984-1986 (платы ЦП)
    image

    Основная выставка шла в хронометрическом порядке хода истории. Началось всё с самых древних методов сложных вычислений:

    Sectors, XV — XVIII
    image

    Lords Calculator, 1880
    image

    Понятия не имею, как на нём можно было что-то считать!

    Schickard Calculator, копия 2000 г. Оригиналы датируются 1623 г.
    image

    Sumador Chino, Mexico, 1800
    image

    Napier's Bones, England, 1700
    image

    Pascal adder (Pascaline), копия, 1981. Оригинал датируется 1641 г.
    image

    Time is Money (TIM) Calculator, 1910
    image

    Curta Calculators, Lichtenstein, 1950 — 1960
    image

    Массово выпускаемые калькуляторы:

    Arithmometer, France, 1850е и ФЕЛИКС М, CCCР, 1932
    image

    И ещё немного разных калькуляторов:
    image

    image

    Type 31 Alphabetical Duplicating punch, IBM, US, 1933
    image

    40 column Card Punch, UK, 1954
    image

    Model 406 Cards Sorter, UK, 1954
    image

    Сортировщики перфокарт от IBM, 1949 и 1953 гг.
    image

    image

    Type 26 Printing Keypunch, IBM, US, 1949
    image

    Hollerith's electric tabulating system, копия. Оригинал датируется приблизительно 1890г.
    image

    Стенд со счётами. Мексиканская мама и мексиканский сынок разбираются, как же что-то на них посчитать
    image

    Nordsieck Differential Analyzer, US, 1956
    image

    Telefunken RAT 700/2 analog computer, Western Germany, 1959
    image

    H-1 Educational Computer, US, 1956
    image

    EAI PACE TR-48 analog computer, US, 1962
    image

    Trice Computer, US, 1964
    image

    MADDIDA, prototype, US, 1949
    image

    LEO II paper tape reader control, UK, 1957
    image

    На этой фотографии моя жена amiora и знаменитость — первый электронный компьютер:

    ENIAC, US, 1945
    image

    Librascope, US, 1956
    image

    Вот он язык, на котором работали эти страшные многотонные железки- FORTRAN
    image

    Вот и ещё одна знаменитость в нашем ХИТ-параде:

    UNIVAC I Supervision Control Console, US 1951
    image

    UNIVAC I Mercury Memory Tank and Vacuum tube chasis, US, 1951
    image

    Среди этих гигантов стоит меленькая, но очень знаменитая машинка.

    ENIGMA, Germany, 1935
    image

    Кстати, рядом на фотографии расположен диск с плёнкой Коллосуса — компьютера, с помощью которого как раз и расшифровывали секретные коды Энигмы.

    JOHNNIAC, US, 1953
    image

    Whirwild Rack, US, 1951
    image

    SAGE Weapons Director Console, US, 1958
    image

    SAGE IBM, US, 1958
    image

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

    BOSCH ABS-2 Conctroller, Germany, 1978
    image

    Norden bombsight «Sight Head», US, 1945
    image

    IBM System/360 Model 30, US, 1964
    image

    А вот стенды с множеством разных поколений хранилищ данных. Многие мы ещё узнаем, но есть совершенно неведомые мне экземпляры:
    image

    image

    Стенд с аппаратами контроля космических миссий:
    image

    VAX-11/780 Comuter, US, 1978
    image

    NEAC 2203, Japan, 1958
    image

    Amdahl 470/V6 Computer, US, 1957
    image

    IBM RAMAC Actuator and disk stack, US, 1956
    image

    UNIVAC Magnetic core memory boar, US, 1956
    image

    Whirlwind magnetic core memory plane, US, 1955
    image

    32k word magnetic core memory unit, US, 1978
    image

    Примеры разработки Flash памяти разных годов:
    image

    CRAY-1, US, 1976
    image

    Униформа оператора и охлаждающий юнит CRAY-1
    image

    Kitchen Computer, US, 1969
    image

    Fairchild «Channel F» Video Intertainment Computer, US, 1976
    image

    Разные поколения процессоров Intel x86
    image

    В разделе робототехники показаны сотни разных роботов, например,

    Shakey, US, 1969
    image

    И другие товарищи
    image

    image

    3620 LISP Workstation, US, 1983
    image

    LMI LAMBDA, US, 1986
    image

    HP 7586B Graphic Plotter, US, 1984
    image

    Professional Iris 4D/50GT, US, 1988
    image

    AutoDESK AutoCAD, US, 1986
    image

    Первые лазерные принтеры:

    HP LaserJet (Aka LaserJet Classic), US, 1984
    Apple Laser Writer Plus, US, 1985
    image

    Nintendo Game Boy, Japan, 1989
    image

    Огромное количество игровых консолей
    image

    image

    Наш герой!!!

    IBM PC, US, 1981
    image

    Apple II, US, 1977
    image

    Коллекция телефонов 1990 — 1999 гг.
    image

    Google Server, 1999
    image

    К сожалению, я не смог полностью передать атмосферу музея, но всем советую, если будет возможность, обязательно посетите этот музей. Вход всего $15, а удовольствия море.

    Спасибо за внимание!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Удобная синхронизация файлов

    Примерно два года назад я родил проект- небольшая программа клиент, которая ставится на любой девайс и просто синхронизирует файлы.
    Например можно было задать, что документы будут синхронизироватся между домашним и рабочим компьютером. Музыку и книги между домашним компом и телефоном. Резервное копирование между домашним компом, рабочим компом и сервером. Также эта программа могла контролировать последующее распространение любого файла в системе. Т.е вы как владелец, могли всегда узнать историю файла: копирование на флешку, на другой компьютер, по «электропочте» и т.д.

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

    Да, скажете вы, есть облачные хранилища и зачем оно нужно когда есть Яндекс.Диск, Dropbox и куча облачных сервисов хранения файлов. Ну просто это не всегда приемлемо и удобно. Минусы:
    1. Вы доверяете свои файлы третьей стороне без всяких гарантий.(Я не параноик, но вы ведь не оставите в таком хранилище ваши интимные данные)
    2. Для доступа к ним нужен интернет. А это в России до сих пор не всегда возможно с необходимой скоростью.

    Свято место пусто не бывает и компания BitTorrent выпустила нечто подобное, но в урезанном виде. Их программа просто синхронизирует файлы между разными платформами и системами как только они вышли в интернет или оказались внутри одной подсети. К сожалению нельзя гибко настраивать правила синхронизации, зато есть отличный клиент который администрируется через либо через нативный интерфейс(WIndows, MAC OS X, Android, iOS), либо через веб интерфейс(*NIX).

    Я больше не лезу за фотками, документами и музыкой на мобилу и не лезу на сервер чтобы забрать редко обновляемый бэкап.
    В домашнем компьютере есть несколько папок:
    Телефон
    Сервер
    Общая
    Авто

    Чтобы закинуть что-то в телефон, я просто копирую нужный файл в папку «Телефон». На моем телефоне он появится через несколько секунд
    Чтобы обменяться документами с ребятами по работе, я кидаю в папку общая. И через несколько секунд этот файл появлятся у всех нужных мне людей – локально а не в облаке.

    В машине, в качестве медиа центра стоит Google Nexus, по 3G смотрит в интернет. На домашнем компьютере кидаю навигации и музыку в папку Авто. Все автоматом складывается в автомобиль. Из папки Авто/регистратор забираю интересные моменты снятые регистратором(девайс в машине всегда онлайн).
    Экономит массу времени.

    Пожелаем BotTorrent успехов в развитии их замечательного проекта.
    Качаем.
    Доступно в Google Play Market и Apple AppStor. Думаю скоро появится под мобильную версию Windows.

    PS
    Спасибо Мурину Саше за наводку )

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    9 самых важных фактов о мобильной рекламе

    eMarketer прогнозирует, что затраты на мобильную рекламу увеличатся почти до 37 млрд. долларов в 2016 году, по сравнению с 8,4 млрд. в 2012 году (дисплейная и контекстная).

    1. Продажи смартфонов за 2014 год составят более 1 млрд. единиц

    По данным IDC, продажи смартфонов впервые превысят объем в 1 млрд. уже в 2014 году. Совокупно продажи смартфонов и планшетов превысят продажи PC в соотношение 3:1 в 2013 году и 5:1 к 2017 году. Такое быстрое распространение смартфонов, в свою очередь, приведет к «буму» мобильного интернета и росту интереса маркетологов к данному рекламному каналу. Отныне, если маркетологи хотят быть первыми, их стратегия должна быть мобильной.

    image

    2. Смартфоны впервые обгонят по продажам «простые» телефоны в 2013 году

    Наконец-то это становится реальностью! Мировые продажи смартфонов обгонят «фичерфоны», благодаря значительному снижению цен и распространению 3G/4G сетей. IDC прогнозирует объем отгрузок смартфонов в 2013 году на уровне 918,6 млн. штук, что составит около 50,1% от общего объема поставок в отрасли. Высокий спрос обеспечивают развивающиеся страны с большой численностью населения: Китай, Индия, Бразилия. Маркетологи должны коренным образом изменить свои маркетинговые стратегии, чтобы ответить на эти радикальные изменения в структуре пользовательских устройств и соответствующим им моделям потребления.

    image

    3. Мобильные устройства завладевают нашим медиа вниманием

    image
    Пользователи мобильного интернета уже тратят больше времени на своих устройствах, даже чем на просмотр ТВ. Среднее время пользование смартфонами составляет 108 минут от общих 7 часов медиа потребления в день, опережая использования компьютеров (93 минуты) и ТВ (92 минуты). Планшеты (37 минут) занимают 5-ое место по медиа потреблению, уже догоняя радио (52 минуты).

    4. Мобильный трафик растет быстро, в отличие от затраты на мобильную рекламу

    Мобайл составляет 15% от общего интернет-трафика и его доля растёт, в среднем, на 50% в год (и скорей всего, темп роста будет только ускоряться). Тем не менее, рекламные бюджеты не торопятся в след за пользователями мобильных устройств. Даже странах с развитой мобильной рекламой, как США, несоответствие медиавлияния и затрат на рекламу около 20 млрд. долларов.

    image
    image

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

    Популярность мобильных приложений постоянно растет. Показы рекламы в мобильных приложениях составляют 75-80% от общего числа. Согласно опросу, 27% респондентов заявили, что использовали 6-10 приложений за последние 30 дней. Будь это бренд-менеджер, которые ищет точку контакта с потребителями или медиапланнер в поисках целевой аудитории — мобильные приложения будут играть главную роль в этом.

    image

    6. Мульти-скрин на подъеме

    Мультискриннинг — это явление одновременного использования потребителем более 1 устройства. Так, примерно, 62% потребителей совмещают использование мобильного устройства с просмотром ТВ. Среди аудитории 20-34, в среднем, 69% потребителей ищут на своих мобильных устройствах информацию, которую только что видели по ТВ. Эти факты имеют огромное влияние для маркетологов, так как рекламные кампании могут становиться действительно многоканальными и дополняющими друг друга.

    7. Rich Media форматы оказывают влияние на вовлечение потребителя


    image

    Мобайл предоставляет брендам простор для творчемства и креатива в рекламе, который до сих пор ограничен ТВ. Rich Media мобильная до 4-х раз более эффективна по сравнению со стандартными баннерами, с точки зрения CTR. Также мобильная реклама размещенная внутри приложений, в среднем, в 1,7 раза более эффективна по отношению к мобильному интернету. Rich Media мобильная реклама достигает показателя CTR 1,53%, когда показывается внутри приложений и «всего» 1,12% в мобильном интернете (что тоже очень хороший результат). Для сравнения, стандартные баннеры имеют CTR 0,39% и 0,32% соответственно.

    8. Потребители не против мобильной рекламы

    Бренды и маркетологи ищут взаимодействия с потребителями через их мобильные устройства в течение всего дня. Наши гаджеты всегда находятся онлайн, увеличивая шансы рекламного сообщения быть увиденным. Согласно исследованиям, 59% всех пользователей мобильных устройств относятся к мобильной рекламе, также как к ТВ-рекламе и рекламе в «большом» интернете.

    9. Мобильная реклама максимально приближает к покупке


    image

    Мобильная реклама напрямую влияет на поведение покупателей. Согласно результатам исследования, 75% всех опрошенных заявили, что они обнаружили что-то новое с помощью своих мобильных устройств. И почти половина (46%) сказали, что они купили что-то с помощью своих мобильных устройств. А 45% опрошенных сообщили, что реклама увиденная на их смартфонах и планшетах напрямую повлияла на их выбор непосредственно в магазине. И вправду, многие люди уже не расстаются с мобильными устройствами, даже находясь прямо перед полками с товаром.


    По вашему мнению, в каком году «выстрелит» мобильная реклама в России?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 68 человек. Воздержалось 37 человек. Источник: habrahabr.ru,
    получено с помощью rss-farm.ru




    2013



    2014



    2015



    2016



    2017



    Да уже давно «выстрелила»



    Никогда этого не будет

    Несколько интересностей и полезностей для веб-разработчика

    Доброго времени суток уважаемые хабравчане. За последнее время я увидел несколько интересных и полезных инструментов/библиотек/событий, которыми хочу поделиться с Хабром.

    Webflow


    С помощью данного сервиса вы сможете сверстать кроссбраузерный отзывчивый макет за 55 минут. Очень красивый и удобный интерфейс. Идеальное решение для веб-дизайнеров, 26 000 из которых уже используют Webflow. Для создания двух проектов сервис бесплатный, а в дальнейшей перспективе вас ждут вполне демократичные цены. Инструмент реально «крутой».

    Если Вам GUI для верстки не комильфо сам по себе как для меня, все равно рекомендую зарегистрироваться и экспортировать парочку responsive макетов. А еще есть простой генератор отзывчивого лэйаута и Responsive Patterns.

    Parallax.js

    Функциональный и простой инструмент для создания параллакс эффекта.


    Для всех элементов на которых будет применяться эффект указываем класс
    layer и устанавливаем значение скорости движения в аттрибуте data-depth
    . В библиотеке есть ряд параметров:
    <code class="html"><ul id="scene"
      data-calibrate-x="false" // Отключает калибровку по горизонтали
      data-calibrate-y="true"  
      data-invert-x="false"     
      data-invert-y="true"  // Устанавливает инверсию по вертикали
      data-limit-x="false"
      data-limit-y="10" // Устанавливает ограничение в 10 циклов для движения
      data-scalar-x="2"
      data-scalar-y="8" // Устанавливаем чувствительность движения
      data-friction-x="0.2"
      data-friction-y="0.8"> // Как я поннимаю это хаотичность движения элементов
      <li class="layer" data-depth="0.00"><img src="layer6.png"></li>
      <li class="layer" data-depth="0.20"><img src="layer5.png"></li>
      <li class="layer" data-depth="0.40"><img src="layer4.png"></li>
      <li class="layer" data-depth="0.60"><img src="layer3.png"></li>
      <li class="layer" data-depth="0.80"><img src="layer2.png"></li>
      <li class="layer" data-depth="1.00"><img src="layer1.png"></li>
    </ul>
    </code>
    После чего передаем родительский элемент в Parallax конструктор:
    <code class="javascript">var scene = document.getElementById('scene');
    var parallax = new Parallax(scene);
    </code>

    Intention.js

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


    Device.js
    Cкрипт по принципу Modernizr присваивает тегу HTML классы
    ios/android/windows/blackberry   phone/tablet   landscape/portrait, тем самым избавляет Вас от необходимости прописывать основные разрешения устройств в media queries. 

    Говоря о «кроссдевайсности» хочется также упомянуть про Risizer — Bookmark для для тестирования отзывчивого дизайна. Все мы знаем про множество подобных сервисов, но мне кажется, этот способ самый удобный.

    GistBox


    GistBox синхронизируется с вашим GitHub профилем и в нужном виде отображает Gist лист. Все ваши сниппеты отсортированы по меткам и всегда под рукой. Доступен как расширение для Chrome.

    CSS Modal

    Начну с того, что проект создан одним из членов команды Boilerplate. CSS Modal — самый простой способ добавить в своей проект адаптивное модальное окно:

    Dotdotdot.js, Uikit, HTML2PDF

    Недавно мне понадобилось сокращать абзацы многоточием. Но стандартный text-overflow
    работает только на одной строке с
    no-wrap
    . И на просторах интернета мне повстречался замечательный скрипт (dotdotdot.js), который отлично решает эту задачу.

    Uikit — плюс один к существующим веб фреймворкам со своими особенностями.

    HTML2PDF. Сервис написан на основе Phantom.js. Возможно пригодиться для оформления портфолио в .pdf.

    Большое спасибо всем за внимание.



    Понравилась ли Вам подборка?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 873 человека. Воздержалось 243 человека.


    Да



    Нет


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Записки Фрилансера: Делимся опытом, часть 1

    imageЗдравствуйте, дорогие читатели Хабра!

    Я разрабатываю приложения под iOS и Mac OS. Уже около года занимаюсь фрилансом и, переходя от клиента к клиенту, начал замечать, что в задаче разбираюсь одиножды; а при появлении похожего заказа, просто использую уже разработанные ранее . В серии статей «Записки Фрилансера» я постараюсь осветить некоторые часто встречающиеся в заказах аспекты; напишу подобие шпаргалки, прочитав которую, вы сможете быстро и безболезненно новую технологию в свой проект. Мои заметки ни в коем случае не претендуют на глубокое понимание процессов, но описывают легкий способ закончить заказ в срок.

    Содержание:

    1. Часть 1: Работа с Файлами; Шаблон Singleton; Работа с Аудио; Работа с ; In-App Purchases
    2. Часть 2: Собственные всплывающие окна (Popups); Как использовать Modal Segue в Navigation Controller; Core Graphics; Работа с UIWebView и ScrollView
    3. Часть 3: Жизнь без Autolayout; Splash Screen; Работа с ориентацией девайса в iOS 6+; Сдвиг содержимого UITextField
    4. Часть 4: Google Analytics; Push Notifications; PSPDFKit; Вход в приложение через Facebook; Рассказать друзьям — Facebook, Twitter, Email
    5. Часть 5: Core Data; UITableView и UICollectionView

    Работа с Файлами

    Многие начинающие iOS разработчики натыкаются на следующую проблему: приложение корректно работает в симуляторе, но отказывается работать или работает некорректно на реальном устройстве. Одна из возможных проблем состоит в том, что приложение активно использует файловые ресурсы, неперенесенные в папку документов приложения. Политика Apple такова: вы не можете менять файлы приложения. Единственное место, где можно развлечься — это папка документов. Читать вы можете отовсюду (в рамках своего приложения), а вот писать только в папке документов.
    Значит, при первом запуске, нужно перенести все документы для записи в папку документов! Запросто! Начнем с создания файла Config.h, добавим следующую строчку в Your_App_Name-Prefix.pch (этот файл автоматически добавлен во все файлы вашего проекта):

    <code class="objectivec">#import "Config.h"
    </code>
    Отлично! Теперь все, что есть в Config.h, есть и во всем проекте! Давайте заполним этот файл:

    <code class="objectivec">#define pathToApplicationDirectory [[NSBundle mainBundle] bundlePath] // Путь к папке приложения
    #define pathToDocuments [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] // Путь к документам
    
    #define pathToSettings [[pathToDocuments URLByAppendingPathComponent:@"settings.plist"] path] // Путь к файлу настроек
    #define pathToPopups [[NSBundle mainBundle] pathForResource:@"popups" ofType:@"plist"] // Путь к файлу со всплывающими окнами
    </code>
    Все это делается исключительно для нашего с вами удобства в будущем (работать с файлами мы будем много и хорошо бы избавиться от магических строк).
    Теперь можно приступить к копированию файлов в папку с документами. Файлы settings.plist и popups.plist мы будем часто изменять, так что пункт с копированием необходим. Добавим следующий код в наш application: didFinishLaunchingWithOptions:

    <code class="objectivec">// Я юзер, а не лузер, так что перемещу ресурсы к документам!
    [self placeResourcesToDocumentsDirectory:@{
         @"settings" : @"plist",
         @"popups" : @"plist"}];
    </code>
    И, конечно же, сам метод placeResourcesToDocumentsDirectory:

    Жми меня!
    <code class="objectivec">/*!
     Метод, копирующий файлы из словаря в папку с документами
     /param Словарь с именами файлов 
     */
    - (void)placeResourcesToDocumentsDirectory:(NSDictionary *)resources {
        // Проверим один из файлов, вдруг скопировано уже
        if (![[NSFileManager defaultManager] fileExistsAtPath:pathToSettings) {
            
            for (NSString *fileName in [resources allKeys]) {
                NSString *extension = resources[fileName];
                
                NSURL *storeURL = [pathToDocuments URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fileName, extension]];
                NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:fileName ofType:extension]];
                NSError *error = nil;
                [[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURL error:&error];
            }
        }
    }
    </code>

    Вот и все! Как просто оказалось переместить файлы в нужную папку, не так ли? А получать доступ к файлу и работать с ним можно вот так:

    <code class="objectivec">NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:pathToSettings];
    settings[@"isThisAppCool"] = @YES;
    [settings writeToFile:pathToSettings atomically:YES];
    </code>

    Шаблон Singleton

    Это скорее небольшой сниппет, который может облегчить вам работу с одиночками.
    Singleton.h:

    Жми меня!
    <code class="objectivec"><...>
    // Упростим доступ к синглтону
    #define coolSingleton [Singleton sharedSingleton]
    
    @interface Singleton : NSObject
    + (Singleton *)sharedSingleton;
    <...>
    </code>

    Singleton.m:

    Жми меня!
    <code class="objectivec"><...>
    @implementation Singleton
    
    + (Singleton *)sharedSingleton {
        static Singleton *sharedSingleton = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedSingleton = [[self alloc] init];
        });
        return sharedSingleton;
    }
    <...>
    </code>

    Здесь все просто. Во-первых, мы упростили одной дефиницией работу с синглтоном. Во-вторых, есть один статичный объект класса Singleton. В-третьих, по вызову метода класса sharedSingleton мы получим либо уже существующий объект, либо инициализируем новый. Всегда будет только один объект класса Singleton. В-четвертых, наш синглтон потокобезопасен (спасибо danilNik и AndrewShmig за подсказку!).

    Работа с Аудио

    Здесь нам придется поработать с классом AVAudioPlayer из фреймворка AVFoundation. Принцип действия прост: создаем объект класса AVAudioPlayer с именем определенного файла, подготавливаем его к воспроизведению и запускаем, когда нужно. Создадим простой синглтон, который и будет содержать все наши аудиоплееры. У нас будет два аудиоплеера: один для фоновой музыки, второй для воспроизведения звука нажатия кнопки.

    Посмотрим на SimpleAudioPlayer.h:

    Жми меня!
    <code class="objectivec">#import <Foundation/Foundation.h>
    #import <AVFoundation/AVFoundation.h>
    
    #define audioPlayer [SimpleAudioPlayer sharedAudioPlayer]
    
    @interface SimpleAudioPlayer : NSObject
    @property (nonatomic, retain) AVAudioPlayer *backgroundMusicPlayer;
    @property (nonatomic, retain) AVAudioPlayer *buttonSoundPlayer;
    
    + (SimpleAudioPlayer *)sharedAudioPlayer;
    
    @end
    </code>

    И на SimpleAudioPlayer.m:

    Жми меня!
    <code class="objectivec">#import "SimpleAudioPlayer.h"
    
    @implementation SimpleAudioPlayer
    
    static SimpleAudioPlayer *sharedAudioPlayer;
    
    + (SimpleAudioPlayer *)sharedAudioPlayer {
        static SimpleAudioPlayer *sharedAudioPlayer = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedAudioPlayer = [[self alloc] init];
        });
        return sharedAudioPlayer;
    }
    
    - (id)init {
        self = [super init];
        if (self) {
            [self initAudioPlayers];
        }
        return self;
    }
    
    /*!
      Метод, инициализирующий аудиоплееры
     */
    - (void)initAudioPlayers {
        NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:pathToBackgroundAudio];
        self.backgroundMusicPlayer = [[AVAudioPlayer alloc]
                            initWithContentsOfURL:fileURL error:nil];
        [self.backgroundMusicPlayer prepareToPlay];
        self.backgroundMusicPlayer.numberOfLoops = -1;
        
        fileURL = [[NSURL alloc] initFileURLWithPath:pathToButtonAudio];
        self.buttonSoundPlayer = [[AVAudioPlayer alloc]
                                  initWithContentsOfURL:fileURL error:nil];
        [self.buttonSoundPlayer prepareToPlay];
    }
    </code>

    Вот и все. Дефиниции путей к аудиофайлам можно прописать в Config.h. Стоит отметить, что мы указали отрицательное число для количества повторений фоновой музыки. Если вы установите отрицательное число у этого свойства — то аудиофайл будет повторяться бесконечно. То, что надо! Так же не стоит забывать о методе prepareToPlay — если подготовить все аудиоплееры, как только приложение запущено, то не будет маленькой задержки перед первым воспроизведением аудиофайла. А пользоваться нашим аудиоплеером можно вот так:

    <code class="objectivec">[audioPlayer.backgroundMusicPlayer play];
    <...>
    [audioPlayer.backgroundMusicPlayer stop];
    </code>

    Работа с видео

    Поработаем немного с фреймворком MediaPlayer. Фактически, следующий код можно добавить даже в метод viewDidAppear:

    <code class="objectivec">NSURL *url = [[NSURL alloc] initFileURLWithPath:pathToMovie];
    MPMoviePlayerViewController *movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
    [self presentMoviePlayerViewControllerAnimated:movieController];
    [movieController.moviePlayer play];
    </code>
    Этот код просто показывает видеофайл по данному URL. В видеопроигрывателе от Apple уже есть все нужные кнопочки, чтобы видеопроигрыватель закрыть. Так что четыре строчки выше — минимальный набор символов для включения видео в ваше приложение.

    In-App Purchases

    Ну, и самое интересное на сегодня: фреймворк StoreKit! Правда, работать мы будем не напрямую с ним, но с MKStoreKit. Огромное спасибо MugunthKumar за великолепный фреймворк!

    Все просто: отредактируйте файл MKStoreKitConfigs.plist под ваши нужды (там все интуитивно понятно) и используйте следующий код для проверки покупок:

    <code class="objectivec">if ([MKStoreManager isFeaturePurchased:@"me.identifier.coolapp.somesinglefeature"]) {
    // Юзер уже купил эту фишку! Нужно ее ему отдать!
    }
    if ([MKStoreManager isSubscriptionActive:@"me.identifier.coolapp.somesubscription"]) {
    // Вау! Да мы можем тянуть деньги ежемесячно, еженедельно, ежедневно! Но сегодня юзер уже заплатил, отдадим ему заслуженную плюшку
    }
    </code>
    Для осуществления покупок используйте следующее:

    <code class="objectivec">[[MKStoreManager sharedManager] buyFeature:@"me.identifier.coolapp.somesinglefeature" 
                                    onComplete:^(NSString* purchasedFeature, 
                                                 NSData* purchasedReceipt, 
                                                 NSArray* availableDownloads) {
         NSLog(@"Юзер купил: %@", purchasedFeature);
     }
                                   onCancelled:^ {
         NSLog(@"Юзер отказался покупать :( печально.");
     }];
    </code>

    Заключение

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

    Обо всех ошибках и неточностях статьи прошу писать в мой хабрацентр.

    P.S. Если вы хотите сотрудничать со мной, то мой профиль есть на одной из крупных бирж фрилансеров.

    Стоит ли продолжать серию статей «Записки Фрилансера»? Выразите свое мнение в комментариях.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Свежие впечатления о BlackBerry 10 NDK

    image

    Последние две недели я снова копался в BlackBerry 10 NDK, так как один из моих клиентов попросил помочь ему. Я предложил адаптировать свой курс «введение в Qt» под платформу BlackBerry, а также порекомендовал следовать советам из моей серии учебных роликов про BB10 и Cascades, опубликованных в начале этого года на YouTube. Теперь мне хочется поделиться с вами моими свежими впечатлениями о BlackBerry 10 NDK. Кстати, я уже писал о моих первых экспериментах с BB10 NDK этой весной.

    Внимание. Это вольный перевод заметки Йэнса Веллера. Перевод сделан для составления общей картины о текущем состоянии мира [BB10 + Qt]. Приятного чтения.

    Приложения и C++
    Перед тем как начать, небольшое введение о приложениях и C++. Люди, переходящие с других языков, вроде Java или .NET, часто не понимают необходимости написания приложений именно на C++. Особенно переходящие с языков, принудительно завязанных на ООП и Сборщик Мусора — им непросто понять все концепты, используемые в C++. По-моему, на самом деле, есть много причин использовать C++ для разработки приложений, особенно в связке с таким мощным фреймворком Qt. Одна из причин — производительность, так как C++ действительно ближе к железу, ваше приложение будет кушать минимум батареи. Не говоря уже о том, что имеется потолок роста производительности устройств в будущем, об этом упоминал Герб Саттер в своей заметке «бесплатные пайки закончились» (есть перевод на хабре от webmasconприм. переводчика). Qt Framework теперь доступен и для Android и для iOS, так что C++ и Qt/QML стали действительно мощной комбинацией для создания мобильных приложений.

    NDK и Cascades
    Поэтому, когда вы разрабатываете приложения под BlackBerry 10, вам необходимо начинать именно с BlackBerry NDK. У меня не было достаточно времени поиграть со свежевышедшей 1.2 версией, но IDE на первый взгляд стала заметно лучше и стабильнее. Но 1.2 пока не получила «золотой» статус (фиксация API, уже получилприм. переводчика), поэтому я рекомендую писать под 1.1, разве что вам что-нибудь нужно из 1.2. BlackBerry NDK поставляется вместе с Cascades Framework, API которого вы будете использовать при разработки приложения под BB10. Cascades сделан поверх Qt и использует QML, в то время как у Qt5 есть QtQuick 2, потому что у BlackBerry своя реализация QML, работающая в UI-потоке. Так что QML, созданный под QtQuick1 или 2 не будет работать под Cascades. А ещё Qt5 не полностью поддерживается Cascades — текущая версия основана на Qt 4.8.

    С 2010 года я интересуюсь мобильной разработкой на Qt и QML, раньше был занят MeeGo, а сейчас я с BlackBerry. QML в BB10 немного отличается, в нём используются специальные элементы, например: Container, Pages и Controls, в то время как в QtQuick1/2 предлагает совсем базовые элементы вроде Item или Rectangle. Так что для QML и его API у BlackBerry имеется свой маленький мирок. Тем временем Qt5-приложения можно собрать и запустить на BB10, правда это не будет сопровождаться той степенью интеграции, которую предлагает Cascades.

    QML и C++
    Судя по документации и обсуждениям, основной подход сводится к использованию QML для большинства задач и мостов в C++ только при необходимости. Например, при написании моделей в C++ и декларирования методов класса с помощью
    Q_PROPERTY
    для доступа их QML. Затем бoльшая часть работы происходит на стороне QML. У QML немного способов верификации и проверок на ошибки, например console.assert, но так как QML траслируется в JavaScript и не обладает сторогой типизацией, следовательно, не может проверять соответствие типов. Опечатка в имени переменной приведёт к тому, что QML может не заметить этой ошибки, а посчитать эту переменную объявленной новой. Простой пример:

    <code class="cpp">Container {
        layout: DockLayout {
        }
        Label{
            text:ListItemData.titel
        }
    }
    </code>
    Этот простой элемент для отображения в контейнере
    ListView, через ListItemData
    мы получаем доступ к данным для отображения. Я тут внёс небольшую ошибку, на самом деле элемент называется
    title, а titel
    — это по-немецки. Тем более, немец это не сразу заметит. А QML не заметит тем более. Вы можете вставить любое слово здесь, QML не проверяет такого рода ошибки не во время компиляции, ни во время исполнения. Ничего не будет отображено, возможно вам повезёт обнаружить предупреждение в консоли. Кстати, если правильно настроить IDE, то сообщение точно должно появляться, даже при отладке на устройстве.

    Как с этим бороться? За Cascades скрывается C++ фреймворк, построенный на Qt, так что хотя бы в C++ у нас есть шанс обнаружить это и запротоколировать ошибку. К сожалению, это невозможно обнаружить во время компиляции, но я работаю в этом направлении. Так что
    Q_ASSERT делает проверку во время работы приложени. Для всех элементов из Cascades, задействованных в QML, имеется класс в C++, инстанциирующийся динамически для каждого элемента во время исполнения приложения. Cascades API позволяет искать объекты этих классов и предоставляет способ контроллировать некоторые вещи. Для ListView
    также имеется класс, поставляющий элементы для
    ListView из C++: ListItemProvider
    . У этого классе есть свой интерфейс:

    <code class="cpp">virtual bb::cascades::VisualNode* createItem(bb::cascades::ListView* listview,const QString& type);
    virtual void updateItem(bb::cascades::ListView* listview,bb::cascades::VisualNode* node,const QString& type,const QVariantList& indexPath, const QVariant& data);
    </code>
    Своя реализация этих виртуальных методов позволяет создавать элементы для отображения в ListView и также заполнять их актуальными значениями. BlackBerry предоставляет примеры реализации. К сожалению, эти примеры не испольуют QML, а написаны целиком на C++. Но мне лично нравится использовать QML для UI. А ещё такой ООП-стиль, как в примере от BlackBerry, подразумевает наследование от
    ListItemProvider
    для каждого отдельно взятого
    ListView, а мне хотелось бы решить данную задачу раз и навсегда, так что у меня свой обобщённый ListItemProvider
    . Так как все проверки происходят во время работы приложения, шаблоны C++ — не вариант, давайте взглянем на следующую реализацию. Перед тем как я перейду к crateItem, краткая отсановка на addType, вспомогательном методе для декларирования обработчиков для каждого типа:

    <code class="cpp">void ListViewItemProvider::addType(const QString& type, const QString& qmlasset, const listitem_callback& callback)
    {
        bb::cascades::QmlDocument* doc = bb::cascades::QmlDocument::create(qmlasset);
        if(!doc->hasErrors())
        {
            doc->setParent(this);
            type_map.insert(type,doc);
            callback_map.insert(type,callback);
        }//TODO add additional error checking & handling
    }
    </code>
    Этот метод добавляет различные обработчики для различных типов. Типы описываются в QML с помощью объектов
    QString, так что QMap<QString, QmlDocument*>
    будет достаточно для хранения поддерживаемых типов. Данный метод преобразует qml-ресурс (например,
    file:///partial.qmlприм. переводчика) в QmlDocument
    с помощью
    QmlDocument::create. Между прочим, QmlDocument::create
    на самом деле не возвращает
    QmlDocument*, как написано в примере выше. Он возвращает ссылку на служебный класс Builder
    для создания
    QmlDocument'ов, затем, похоже, производит неявное преобразование в QmlDocument*
    . В принципе, здесь ничего интересного, идём дальше, метод
    createItem:

    <code class="cpp">bb::cascades::VisualNode* ListViewItemProvider::createItem(bb::cascades::ListView* listview,const QString& type) { if(type_map.find(type)!=type_map.end()) { bb::cascades::Container* node = type_map[type]->createRootObject<bb::cascades::Container>(); return node; } Q_ASSERT_X(false,__FUNCTION__,type +" TYPE not handled"); bb::cascades::Container* con = new bb::cascades::Container(0); bb::cascades::Label* label = new bb::cascades::Label(con); label->setText("ERROR"); return con; } </code>Данный код сначала проверяет регистрацию типа, а затем создаёт объект через метод QmlDocument::createRootObject
    , который возвращает указатель на созданный объект. Это шаблон, так что мы должны заранее знать тип объекта для создания. Пока я для себя определился, что для всех UI элементов я буду использовать
    Container в качестве корневого объекта. Возможно, здесь также подойдёт тип VisualNode*
    , который является возвращаемым значением метода
    createItem. Здесь самое интересное — обработка ошибки, как мы должны это сделать? Тут на помощь приходит Q_ASSERT_X
    и оповещает об ошибке. Но в случае сборки без отладки он ничего не сообщит, а тем не менее метод должен вернуть какое-либо значение. Про 0 ничего не сказано в документации, поэтому нет оснований думать, что это верное возвращаемое значение для данного метода. Но зато в документации явно указано, что возвращаемый указатель будет принадлежать
    ListView Даже если мы вернём 0 (к счастью, разработчики BB10 предусмотрели это), это утаит ошибку от тестировщика. Так что я решил возвращать небольшой Container
    с
    Label с текстом об ошибке. Может быть, я мог бы сформулировать сообщение лучше, но в данном варианте тестер скорее заметит эту ошибку. Как вариант, можно было бросить исключение, но после этого контроль передаётся обратно в Cascades API и Qt, а это не лучший вариант, так как Qt и Cascades не используют исключения, хоть они и поддерживаются в BB10.

    Последнее, что нужно реализовать — метод updateItem
    . И снова не получается обойтись проще, ведь мы пишем обощённый код. В конце концов, загружаемый QML файл должен быть загружен с правильными значениями, что также явилось одной из причин, почему я решил написать велосипед реализовать обобщённый подход. Но есть вариант с заимствованием реализации для этого прямо из нашего класа — мы регистрировали callback'и для создания объектов нужных типов, теперь остаётся просто вызвать соответствующий callback в методе
    updateItem:

    <code class="cpp">if(callback_map.find(type)!=callback_map.end()) { #ifndef USE_BOOST (*callback_map[type])(node,indexPath,data); #else callback_map[type](node,indexPath,data); #endif } </code>До этого момента я мог не использовать/скрыть дефайн USE_BOOST
    , но для такого callback'а программист С++ должен сначала учесть
    boost::function. И так как BlackBerry утверждает, что boost поддерживается, я конечно же использую его. И тут выходит, что это не так-то просто, по крайней мере мой тулчайн падает с ошибкой в boost/type_traits/detail/cv_trait_impl.hpp
    . Я знаю, что boost используется многими, так что это скорее всего ошибка из-за настроек моего тулчайна или дистрибутива Linux. Ошибка судя по всему идёт из препроцессора, на версии GCC 4.6.3, в тексте ошибки сказано про несовпадение скобок. Я предпочёл пропатчить мою версию boost на локальной машине и сообщил об этом в сообщество boost и в BlackBerry. Если вы используете boost под BB10, то вам лучше использовать версию boost с GitHub'а BlackBerry. Так как не всем нужен boost, я также сделал версию без него, на случай если boost поломается снова.

    И последнее, но не менее важное, реализация callback'a:

    <code class="cpp">void ApplicationUI::callbackMyListItem(bb::cascades::VisualNode* node,const QVariantList& indexPath, const QVariant& data)
    {
        bb::cascades::ImageView* image = node->findChild<bb::cascades::ImageView*>("imageview");
        Q_ASSERT(image);
        if(image)
        {
            QString name_image = "image"; //this must be correct!
            QVariantMap map = data.toMap();
            bool hasdata = map.contains(name_image);
            Q_ASSERT(hasdata);
            if(hasdata)
                image->setImageSource(map[name_image].toUrl());
        }
    }
    </code>
    В данном случае путь до изображения задан. Указатель на
    VisualNode унаследован от QObject
    , так что дочерние объекты могут быть получены через
    findChild, который вернёт 0 в случае, если ничего не будет найдено. Поэтому уместно использовать здесь Q_ASSERT
    для проверки этого случая. Затем происходит поиск данных в
    QVariantMap. Так как нам в любом случае нужно какое-либо изображение, проверяется наличие элемента в контейнере QVariantMap. Если его нет, то Q_ASSERT
    снова приходит на помощь. Этот callback просто регистрируется с помощью
    boost::bind.

    Поиск значений также может быть реализован через модель, но BB10 не поддерживает обычные модели из Qt, вместо этого BlackBerry реализовали свои классы моделей. В целом это хорошо, но мне лично больше нравятся модели из Qt, тем более это позволило бы использовать их при портировании Qt-приложения под Android, iOS, PC/Mac или даже Jolla. KDAB — один из наших «золотых» спонсоров — опубликовал решение, которое устраняет это недоразумение и делает Qt-модели пригодными для использования в Cascades.

    IDE
    Теперь, пару слов об IDE. Как я уже сказал ранее, IDE улучшилась с выходом версии 1.2. Среда улучшается, но в некоторых случаях всё равно остаётся далёкой от совершентсва. Редактор QML по-прежднему не достаточно хорош, зато теперь при падении не роняет всю IDE. Альтернативой мог бы стать Qt Creator, в нём поддержка QML также улучшилась. На данный момент, мне кажется Momentics IDE (базируется на Eсlipse — прим. переводчика) от BlackBerry лучше, чем QtCreator, если речь о разработке под Cascades. Во-первых, в QtCreator нет интеграции с Cascades вообще, поэтому автодополнение QML работать не будет, потому как в NDK отсуствтует необходимый для этого файл. По этой же причине не будет работать визуальный редактор QML. Qt, конечно, чуть лучше поддерживается в QtCreator, но в 1.2 версии NDK действительно много улучшений в этом направлении. Шаблоны проектов, предлагаемые QtCreator, не такие хорошие, как в Momentics, например, в них отсутствует интеграция кода локализации. Мне нравится то, что шаблоны в Momentics включают QTranslator в main.cpp
    . Momentics и QtCreator обма могут создать рабочее приложение под моё DevAlpha устройство, так что под BB10 в QtCreator возможна, но есть куда расти.

    Я загрузил исходные коды ListViewItemProvider, если вам нужно…

    Популярные комментарии (1 шт)
    — Кто хочет навестить морг?

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    AndEngine GLES2 — Живые обои

    Зимой прошлого года (скорее всего в солнечный день:) я заинтересовался графической библиотекой AndEngine, так как захотелось поработать с двумерной графикой на мобильном телефоне (с использованием OpenGL), и это решение мне показалось наиболее интересным и доступным. Сделав несколько графических приложений, я решил создать живые обои, тем более что в поставке с AndEngine идёт специальная библиотека для создания таковых. Теперь поделюсь своим опытом создания живых обоев с вами.
    Специально для этого я подготовил проект (обладает обильными комментариями), «шаблон» для показа принципа работы живых обоев.
    image


    Подготовка
    Прежде всего необходимо установить сам AndEngine и в частности библиотеку AndEngineLiveWallpaperExtension (рекомендую сразу установить все доступные библиотеки) так как она будет являться базой. Так как эта статья не является базовой для изучения AndEngine я не буду рассказывать как установить библиотеки, тем более что данную информацию вы можете легко найти, например здесь — http://www.matim-dev.com/how-to-setup-andengine.html. Теперь вам необходимо открыть прилагаемый проект и запустить его. Если он сразу не запустится, то скорее всего вам необходимо проверить подключенные библиотеки к проекту. В итоге у вас должно получиться что то типа этого — http://youtu.be/HRKzBma9vz0

    Функционал
    А теперь кратко и по порядку (большая часть функционал также относится ко всем другим AndEngine GLES2 приложениям). Предком главного класса проекта является «BaseLiveWallpaperService», именно этот класс отвечает за всю работу с GLES2. Обязательными для переопределения являются функции:
    <code class="java">onSurfaceChanged
    onCreateEngineOptions
    onCreateResources
    onCreateScene
    </code>
    public void onSurfaceChanged(final GLState pGLState, final int pWidth, final int pHeight) — функция определения размера экрана и установки камеры.
    public EngineOptions onCreateEngineOptions() — функция настройки работы движка живых обоев. Данная функция возвращает в систему выбранные параметры для настройки GLES2.
    public void onCreateResources(OnCreateResourcesCallback pOnCreateResourcesCallback) — как понятно из названия, данная функция предназначена для создания всех (медиа) ресурсов которые будут участвовать в работе приложения.
    public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) — функция создания сцены и размещения на ней всех желаемых объектов.

    Загрузка тестур
    Загрузка текстуры происходит в три этапа: определение атласа; определение текстуры; загрузка текстуры в атлас. Рассмотрим их на примере загрузки заднего фона:
    <code class="java">this.mOnScreenControlTexture0 = new BitmapTextureAtlas(this.getTextureManager(), 1930, 1050, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
    this.bg_TextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mOnScreenControlTexture0,this,"gfx/bg.jpg", 0, 0);
    this.getEngine().getTextureManager().loadTexture(this.mOnScreenControlTexture0);
    </code>
    В первой строке определяется размер для атласа текстур. Нужно заранее определить какие текстуры и в каком порядке расположатся на данном атласе и рассчитать его размер. Если неправильно рассчитать положение текстур в атласе или сделать его меньше требуемого размера, то программа будет работать не корректно. В нашем случае в атласе будет располагаться всего одна картинка (спрайт) и поэтому размер атласа будет ровняться размеру картинки.
    В случае если требуется загрузить две картинки (спрайта) и более, то размер атласа придётся высчитывать. Например: Мы хотим загрузить две картинки размером 60*60 и 80*75 пикселей. Для нахождения ширины атласа сложим ширину первой и второй картинки, получим 140. При этом высота атласа должна ровняться наибольшей из этих картинок. При необходимости компоновка атласа может быть любой сложности, всё ограничивается только фантазией программиста и максимальными размерами (2048*2048).
    image
    Во второй строке определяется объект через который в дальнейшем можно получить интересующую текстуру. Аргументы конструктора следующие: атлас для хранения текстуры; контекст; адрес расположения текстуры; координата по Х, начиная с которой располагается текстура; координата по Y, начиная с которой располагается текстура. Все текстуры должны храниться в парке «gfx» (проект/assets/gfx).
    В третьей строке находится сам загрузчик, с помощью которого загружается вся графика в атлас.

    Создание сцены
    Сцена создается всего одной строкой — mScene= new Scene(), далее происходит самое интересное — размещение всех нужных объектов на сцене. Главной строительной единицей всех приложений строящихся с помощью AndEngine, являются спрайты (так как библиотека работает исключительно с двумерными объектами). Рассмотрим пример создания простого спрайта:
    <code class="java">bg = new Sprite(0, 0, this.bg_TextureRegion, getVertexBufferObjectManager());
    bg.setSize(bg.getWidth() * 2, bg.getHeight() * 2);
    bg.setPosition(10, 20);
    mScene.attachChild(bg);
    </code>
    В первой строке создаётся спрайт. У конструктора следующие аргументы: положение на сцене по оси Х; положение на сцене по оси Y; объект текстуры; менеджер буфера. Во второй строке переопределяется размер спрайта, по умолчанию он равен размеру текстуры. В третьей строке переопределяется позиция спрайта на экране. В четвертой строке спрайт непосредственно добавляется на экран.
    Если вы посмотрите код прилагаемого примера, то заметите что в нем определен класс Sun. Он является потомком класса Sprite. В этом классе прописана логика анимации объекта, которая заключается в повороте объекта относительно своего центра.
    Также определен класс LiveWallpapperSettings, который отвечает за настройку живых обоев. Так как это достаточно стандартная вещь, логику работы настроек описывать не буду (интересующую информацию вы легко найдете в Яндексе либо в других поисковых машинах).

    Заключение
    Библиотека очень проста в использовании и функциональна. Главным её недостатком является механизм замораживания, который срабатывает при скрытии обоев и не всегда отключается при продолжении их показа. Данный минус явно прослеживается когда обои имеют относительно большое количество спрайтов на сцене (как например здесь — https://play.google.com/store/apps/details?id=com.livewallpaper.summermeado_wfull). Если кто-то решил проблему с замораживанием, пожалуйста поделитесь решением.
    Я намеренно не стал раздувать пример и добавлять максимальное количество функционала чтобы показать, что графические приложения для Android это быстро и просто.
    Удачного тестирования!

    Проект живых обоев — http://www.anprog.com/documents/AE_gles2_LiveWallpaper.zip

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    В Google обосновали свой проект планетарного интернета Loon с точки зрения распределения воздушных шаров в стратосфере

    В августовском интервью Bloomberg Билл Гейтс грубовато дал понять, что он думает по поводу проекта Google, известного как Project Loon — речь идёт о системе воздушных шаров для возможности подключения к интернету жителей удалённых районов планеты:
    Когда вы умираете от малярии, я полагаю, вы можете посмотреть вверх и увидеть воздушный шар, но я не уверен как это может вам помочь. Когда у ребенка диарея, то нет сайта, который бы смог его вылечить.
    ОригиналWhen you’re dying of malaria, I suppose you’ll look up and see that balloon, and I’m not sure how it’ll help you. When a kid gets diarrhea, no, there’s no website that relieves that.

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

    Один из сотрудников проекта Ден Пипони (Dan Piponi) выполнил компьютерную симуляцию проблемы и теперь его результаты доступны публично. Главный ответ — да, устойчивое покрытие вполне возможно.

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



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

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

    с объяснением самого Дена можно посмотреть ниже:


    [Источник]

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    27-29 октября 2013: Конференция для разработчиков Samsung Developer Conference

    Привет, Хабр!

    Мы рады сообщить, что c 26 августа открыта регистрация на первую ежегодную конференцию для разработчиков, которую организует компания Samsung Electronics и которая пройдёт в Сан-Франциско в Westin St. Francis Hotel в период с 27 по 29 октября 2013 года.



    В ходе конференции лучшие специалисты со всего мира выступят с десятками технических сессий на следующие темы:

    • Новые средства разработки Samsung, такие как S Pen, и новые возможности;
    • Погружение в Samsung Service Platform, API для ChatON, Group Play, Samsung AdHub, Context Aware и многое-многое другое;
    • Мастер-классы по разработке приложений для Smart TV с поддержкой дисплеев различных размеров и разрешений;
    • Новые возможности в разработке игр;
    • Кросс-платформенная HTML5-приложений;
    • Разработка Web-приложений для Tizen;
    • Специальные сессии для B2B-разработчиков, где будет рассказано о программе для мобильных партнёров, о создании сертифицированных приложений, KNOX, Enterprise SDK и многом другом.
    Стоимость участия в конференции составляет $299. Подробности можно узнать на официальном сайте мероприятия: samsungdevcon.com Также уже доступна предварительная программа мероприятия.

    Приглашаем всех желающих принять участие в этом знаменательном событии!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Pro Core Data for iOS. Глава №2. Практическая часть

    Хабралюди, добрый день!
    Сегодня хочу начать вольный перевод книги Михаеля Привата и Роберта Варнера «Pro Core Data for iOS», которую можете скачать по этой ссылке. Каждая глава будет содержать теоретическую и временами практическую часть.

    image

    Содержание:
    • Глава №1. Приступаем (Практическая часть)
    • Глава №2. Усваиваем Core Data (Практическая часть)
    • Глава №3. Хранение данных: SQLite и другие варианты
    • Глава №4. Создание модели данных
    • Глава №5. Работаем с объектами данных
    • Глава №6. Обработка результатирующих множеств
    • Глава №7. Настройка производительности и используемой памяти
    • Глава №8. Управление версиями и миграции
    • Глава №9. Управление таблицами с использованием NSFetchedResultsController
    • Глава №10. Использование Core Data в продвинутых приложениях


    Вступление
    Будем мы создавать вот такую модель:
    image

    Затем добавим несколько записей и запросим их. Вывод будет производиться в консоль, чтобы мы не задавались еще и вопросами визуальными.
    Готовы? Тогда поехали!

    Описание
    Будем создавать объектный граф нашего любимого ресурса — Хабра.
    Есть N основных объектов:
    • Запись в блоге
    • Пользователь
    • Теги
    • Хабы
    • Вопросы
    • Ответы
    • Учетная запись компании
    Этого будет достаточно.

    Какие данные содержит каждый из объектов?
    • Запись в блоге — заголовок, текст
    • Пользователь — ник, карма, рейтинг, пол, аватар, почтовый ящик
    • Тег — наименование
    • Хаб — наименование, профильный ли хаб
    • Вопрос — заголовок, текст
    • Ответ — текст
    • Учетная запись компании — наименование организации, рейтинг

    Приступаем к работе
    Открываем XCode и создаём новый проект Single View Application:


    Вводим наименование проекта, префиксы и прочее:
    image

    Знакомое окно:
    image

    Добавляем Core Data
    Добавляем Core Data Framework в проект:
    image

    Создаем модели
    Добавить новый файл -> iOS -> CoreData -> Data Model
    image
    image

    Начнём с записи в блоге.
    Создаем новую сущность и называем её Blogpost, добавляем два атрибута caption (String) и text (String).
    image

    Создаем новую сущность и называем её User, добавляем атрибуты avatar (String), email (String), gender (Decimal), karma (Integer 16), nickname (String), rating (Integer 16).
    image

    Создаем новую сущность и называем её Tag, добавляем всего один атрибут name (String).
    image

    Создаем новую сущность и называем её Hab, добавляем два атрибута name (String), target (Boolean).
    image

    Создаем новую сущность и называем её Question, добавляем два атрибута caption (String), text (String).
    image

    Создаем новую сущность и называем её Response, добавляем один атрибут text (String).
    image

    Создаем новую сущность и называем её Organization, добавляем два атрибута name (String), rating (Integer 16).
    image

    Вот что у нас есть в итоге:
    image

    Теперь займемся установкой отношений между объектами.
    У учетной записи компании есть множество пользователей (сотрудников).
    У пользователя есть множество записей в блоге, у записи в блоге есть множество тегов и хабов.
    У пользователя есть множество вопросов, а у вопроса множество ответов.

    Начнем с построение связи «учетная запись компании» (один-ко-многим) «пользователи».
    Выбираем из списка сущностей Organization и добавляем новую связь нажав на "+" в разделе Relationships:
    image
    Так как по умолчанию XCode создаёт связь один-к-одному мы должны изменить тип связи:
    image

    Теперь у каждой организации есть множество пользователей. Поле Inverse (обратная связь) мы сейчас тоже установим, но предварительно добавим новую связь в сущность Пользователя и назовем её organization (организация в которой работает пользователь, а если он не работает нигде, то поле будет null):
    image

    Теперь вновь откроем редактирование сущности Organization и установим поле Inverse в organization:
    image

    Вот как стал выглядеть теперь объектный граф:
    image

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

    Создаем организацию
    Уже имеем в AppDelegate.h такое:
    <code class="objectivec">//
    //  TMAppDelegate.h
    //  Habrahabr
    //
    //  Created by AndrewShmig on 8/31/13.
    //  Copyright © 2013 TM. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @class TMViewController;
    
    @interface TMAppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    @property (strong, nonatomic) TMViewController *viewController;
    
    @property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
    @property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
    @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
    
    @end
    </code>
    И в AppDelegate.m:
    <code class="objectivec">//
    //  TMAppDelegate.m
    //  Habrahabr
    //
    //  Created by AndrewShmig on 8/31/13.
    //  Copyright © 2013 TM. All rights reserved.
    //
    
    #import "TMAppDelegate.h"
    
    @implementation TMAppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        return YES;
    }
    
    #pragma mark - Core Data Stack
    
    - (NSManagedObjectModel *)managedObjectModel
    {
        if(nil != _managedObjectModel)
            return _managedObjectModel;
        
        _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
        
        return _managedObjectModel;
    }
    
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if(nil != _persistentStoreCoordinator)
            return _persistentStoreCoordinator;
        
        NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                                   inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"Habrahabr.sqlite"];
        
        NSError *error = nil;
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
        if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]){
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        
        return _persistentStoreCoordinator;
    }
    
    - (NSManagedObjectContext *)managedObjectContext
    {
        if(nil != _managedObjectContext)
            return _managedObjectContext;
        
        NSPersistentStoreCoordinator *store = self.persistentStoreCoordinator;
        if(nil != store){
            _managedObjectContext = [[NSManagedObjectContext alloc] init];
            [_managedObjectContext setPersistentStoreCoordinator:store];
        }
        
        return _managedObjectContext;
    }
    
    @end
    </code>
    Перепишем метод application:didFinishLaunchingWithOptions: таким образом:
    <code class="objectivec">- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    //    Создаем организацию
        NSManagedObject *yandex = [NSEntityDescription insertNewObjectForEntityForName:@"Organization"
                                                                inManagedObjectContext:self.managedObjectContext];
        [yandex setValue:@"Yandex Inc." forKey:@"name"];
        [yandex setValue:@672 forKey:@"rating"];
        
    //    создаем сотрудников Yandex
        NSManagedObject *pupkin = [NSEntityDescription insertNewObjectForEntityForName:@"User"
                                                                inManagedObjectContext:self.managedObjectContext];
        [pupkin setValue:@"VaseaPup" forKey:@"nickname"];
        [pupkin setValue:@"vasilisa@yandex.ru" forKey:@"email"];
        [pupkin setValue:@1 forKey:@"gender"]; // 0 - unknown, 1 - male, 2 - female
        [pupkin setValue:@0 forKey:@"karma"];
        [pupkin setValue:@0 forKey:@"rating"];
        
        NSManagedObject *gosha = [NSEntityDescription insertNewObjectForEntityForName:@"User"
                                                               inManagedObjectContext:self.managedObjectContext];
        [gosha setValue:@"Goshka" forKey:@"nickname"];
        [gosha setValue:@"gosha.k@yandex.ru" forKey:@"email"];
        [gosha setValue:@0 forKey:@"gender"];
        [gosha setValue:@0 forKey:@"karma"];
        [gosha setValue:@0 forKey:@"rating"];
        
    //    связываем сотрудников с компанией
        NSMutableSet *employees = [yandex mutableSetValueForKey:@"employees"];
        [employees addObject:pupkin];
        [employees addObject:gosha];
        
    //    сохраняем данные в хранилище
        [self saveContext];
        
        NSLog(@"Finish!");
        
        return YES;
    }
    </code>
    Запустим приложение. Данные должны были быть сохранены. Проверим это.
    Найдем файл Habrahabr.sqlite:
    image

    Запустим терминал и проверим структуру БД:
    <code class="bash">AndrewShmigs-MacBook-Pro:~ new$ cd "/Users/new/Library/Application Support/iPhone Simulator/6.1/Applications/95B0716A-9C2C-4BD8-8117-62FB46BB5879"
    AndrewShmigs-MacBook-Pro:95B0716A-9C2C-4BD8-8117-62FB46BB5879 new$ ls
    Documents	Habrahabr.app	Library		tmp
    AndrewShmigs-MacBook-Pro:95B0716A-9C2C-4BD8-8117-62FB46BB5879 new$ cd Documents/
    AndrewShmigs-MacBook-Pro:Documents new$ ls
    Habrahabr.sqlite
    AndrewShmigs-MacBook-Pro:Documents new$ sqlite3 Habrahabr.sqlite 
    SQLite version 3.7.12 2012-04-03 19:43:07
    Enter ".help" for instructions
    Enter SQL statements terminated with a ";"
    sqlite> .schema
    CREATE TABLE ZBLOGPOST ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZAUTHOR INTEGER, ZCAPTION VARCHAR, ZTEXT VARCHAR );
    CREATE TABLE ZHAB ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZTARGET INTEGER, ZBLOGPOSTS INTEGER, ZNAME VARCHAR );
    CREATE TABLE ZORGANIZATION ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZRATING INTEGER, ZNAME VARCHAR );
    CREATE TABLE ZQUESTION ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZAUTHOR INTEGER, ZCAPTION VARCHAR, ZTEXT VARCHAR );
    CREATE TABLE ZRESPONSE ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZQUESTION INTEGER, ZTEXT VARCHAR );
    CREATE TABLE ZTAG ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZBLOGPOST INTEGER, ZNAME VARCHAR );
    CREATE TABLE ZUSER ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZKARMA INTEGER, ZRATING INTEGER, ZORGANIZATION INTEGER, ZGENDER DECIMAL, ZAVATAR VARCHAR, ZEMAIL VARCHAR, ZNICKNAME VARCHAR );
    CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY, Z_UUID VARCHAR(255), Z_PLIST BLOB);
    CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR, Z_SUPER INTEGER, Z_MAX INTEGER);
    CREATE INDEX ZBLOGPOST_ZAUTHOR_INDEX ON ZBLOGPOST (ZAUTHOR);
    CREATE INDEX ZHAB_ZBLOGPOSTS_INDEX ON ZHAB (ZBLOGPOSTS);
    CREATE INDEX ZQUESTION_ZAUTHOR_INDEX ON ZQUESTION (ZAUTHOR);
    CREATE INDEX ZRESPONSE_ZQUESTION_INDEX ON ZRESPONSE (ZQUESTION);
    CREATE INDEX ZTAG_ZBLOGPOST_INDEX ON ZTAG (ZBLOGPOST);
    CREATE INDEX ZUSER_ZORGANIZATION_INDEX ON ZUSER (ZORGANIZATION);
    sqlite> select * from ZORGANIZATION;
    1|3|1|672|Yandex Inc.
    sqlite> select * from ZUSER;
    1|7|1|0|0|1|0||gosha.k@yandex.ru|Goshka
    2|7|1|0|0|1|1||vasilisa@yandex.ru|VaseaPup
    sqlite> 
    </code>
    Добавим теперь одному из сотрудников вопрос и создадим какой-то пост.
    <code class="objectivec">//    добавляем сотруднику Гоше вопрос
        NSManagedObject *whoAmI = [NSEntityDescription insertNewObjectForEntityForName:@"Question"
                                                                inManagedObjectContext:self.managedObjectContext];
        [whoAmI setValue:@"Who am I?" forKey:@"caption"];
        [whoAmI setValue:@"Помогите мне узнать себя лучше." forKey:@"text"];
        
        NSMutableSet *goshasQuestions = [gosha mutableSetValueForKey:@"questions"];
        [goshasQuestions addObject:whoAmI];
    </code>
    Запустим приложение и проверим БД:
    <code class="bash">sqlite> select * from ZQUESTION;
    1|4|1|4|Who am I?|Помогите мне узнать себя лучше.
    sqlite> 
    </code>
    Добавим блогпост сотруднику Васе Пупкину:
    <code class="objectivec">//    добавляем сотруднику Васе Пупкину новый блогпост
        NSManagedObject *newPost = [NSEntityDescription insertNewObjectForEntityForName:@"Blogpost"
                                                                 inManagedObjectContext:self.managedObjectContext];
        [newPost setValue:@"yandex.Деньги & yandex.Карты & yandex.ДваСтвола" forKey:@"caption"];
        [newPost setValue:@"Some text" forKey:@"text"];
        
    //    добавляем два Хаба
        NSManagedObject *hab1 = [NSEntityDescription insertNewObjectForEntityForName:@"Hab"
                                                              inManagedObjectContext:self.managedObjectContext];
        [hab1 setValue:@"iOS" forKey:@"name"];
        [hab1 setValue:@YES forKey:@"target"];
        
        NSManagedObject *hab2 = [NSEntityDescription insertNewObjectForEntityForName:@"Hab"
                                                              inManagedObjectContext:self.managedObjectContext];
        [hab2 setValue:@"Objective-C" forKey:@"name"];
        [hab2 setValue:@YES forKey:@"target"];
        
        NSMutableSet *habs = [newPost mutableSetValueForKey:@"habs"];
        [habs addObject:hab1];
        [habs addObject:hab2];
        
        [[pupkin mutableSetValueForKey:@"blogposts"] addObject:newPost];
    </code>
    И вывод:
    <code class="bash">sqlite> select * from ZBLOGPOST;
    1|1|1|5|yandex.Деньги & yandex.Карты & yandex.ДваСтвола|Some text
    sqlite> select * from ZHAB;
    1|2|1|1|1|iOS
    2|2|1|1|1|Objective-C
    sqlite> 
    </code>

    Вывод данных
    Выведем всех сотрудников и наименования компаний в которых они работают. Код для чтения данных будем писать в том же методе в котором писали и запись данных.
    <code class="objectivec">    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"];
        NSArray *allUsers = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
        
        for(NSManagedObject *user in allUsers){
            NSString *nickname = [user valueForKey:@"nickname"];
            NSString *organization = [user valueForKeyPath:@"organization.name"];
            
            NSLog(@"%@ works at %@", nickname, organization);
        }
    </code>
    Получим примерно такой вывод (приложение у меня запускалось несколько раз и данные тоже несколько раз были добавлены):
    <code class="bash">2013-08-31 13:00:27.255 Habrahabr[18148:c07] Goshka works at Yandex Inc.
    2013-08-31 13:00:27.257 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
    2013-08-31 13:00:27.258 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
    2013-08-31 13:00:27.258 Habrahabr[18148:c07] Goshka works at Yandex Inc.
    2013-08-31 13:00:27.259 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
    2013-08-31 13:00:27.259 Habrahabr[18148:c07] Goshka works at Yandex Inc.
    2013-08-31 13:00:27.260 Habrahabr[18148:c07] Finish!
    </code>
    Обратите внимание на то, как мы получили наименование организации в которой работает пользователь. Как Вам? А? Я так и думал, что понравится!

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

    Удачи и благодарю за внимание!
    Надеюсь вам понравилась практическая часть.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Обзор сетевого хранилища Fantec CL-35B2 RAID

    Я думаю, что нет смысла объяснять хабраюзерам, зачем нужно сетевое хранилище. Скорее всего, многие уже используют этот способ хранения данных у себя дома. Это же категорически удобно – все мультимедийные файлы собраны в одном месте, не нужно таскать фильмы на флешках между рабочим компьютером, ноутбуком и телевизором. Вдобавок ко всему и скачивать файлы существенно проще – компы выключены, в доме тишина, а под столом стоит маленькая коробочка, которая в поте лица качает и раздает торренты. Я долго пользовался однодисковым QNAP TS-119 с диском на 3 терабайта, но желание проапгрейдится на двухдисковое хранилище и увеличить объем было непреодолимо. В итоге в мои руки попал Fantec CL-35B2 RAID, о нем и пойдет речь под катом. В первую очередь девайс удивил своими габаритами, я ожидал увидеть существенно бОльшую коробку. Рассказывать подробно о коробке, честно говоря, не хочется. Просто приведу несколько фотографий с акцентом на технологии, которые Fantec считает нужным выделить в своем устройстве: поддержка двух жестких дисков и гигабитный интерфейс.


    Упакован NAS качественно, при транспортировке вряд ли что-то может случится с пустым хранилищем. Но в случае, если вы заказываете NAS с установленными дисками, масса устройства возрастает существенно и тогда почтовые службы существенно увеличивают свои шансы на разгром посылки.
    В комплекте поставки: собственно сетевое хранилище, адаптер питания, сетевой кабель RJ -45, диск с программным обеспечением.
    NAS выглядит вполне симпатично. Передняя панель выполнена из глянцевого черного пластика, сам корпус – из крашеного алюминия. Решение вполне логичное, корпус выполняет также функции радиатора для дополнительного охлаждения жестких дисков. Передняя панель сетвеого хранилища отведена под кнопочки и индикаторы. Здесь расположились кнопка включения, индикатор питания системы, индикаторы активности жестких дисков (по одному для каждого из дисков), индикатор ошибок, индикатор копирования с USB носителя, кнопка копирования с USB накопителя и разъём USB для подключения устройств с информацией.
    Обратная сторона NAS отведена под вентилятор системы охлаждения, гнездо для подключения блока питания, разъём для подключения локальной сети RJ-45, USB разъём, кнопка Reset и гнездо для Kensington lock.
    Нижняя панель кроме резиновых ножек также содержит элементы, ответственные за работу NAS, а именно защелку для передней панели и два отверстия для крепления установленных жестких дисков.

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

    После снятия алюминиевого корпуса остается весьма жалкая конструкция, вовсе не напоминающая сетевое хранилище или какой-либо компьютер в принципе.
    Основа NAS Fantec CL-35<span style=«mso-ansi-language:EN-US» lang=«EN-US»>B2 RAID — чип PLX NAS 7821. Обращение к Гуглю приводит на сайт производителя этого контроллера: www.plxtech.com/products/consumer/nas7821 — по ссылочке можно посмотреть документацию, а при наличии подписанного NDA с PLX скачать киты для разработки. У меня никаких соглашений с вендором нет, поэтому почитаем только то, что доступно всем. Тут начинаются первые сюрпризы, например поддерживается только интерфейс SATA 3 ГБит/с. Не то, чтобы очень надо было или пропускная способность гигабитного Ethernet позволяла прокачивать через себя больше одного гигабита, но тем не менее, хотелось бы видеть SATA III (6 ГБит/с) интерфейс.  Внутрь NAS тем не менее буду ставить диски SATA III — специально обученные для работы в сетевых хранилищах, прошедшие спецподготовку на секретных базах и получившие красные наклейки — Western Digital WD30EFRX NASware или по-простому — WD Red.
    Установка проходит очень просто и беспроблемно — вставляем диск нужной стороной в отсек (наклейкой к центру NAS) и фиксируем одним винтом с нижней панели — вуаля, NAS собран и готов к работе.
    После включения в сеть (220В) и сеть (LAN) девайсу будет назначен IP и по нему можно зайти в веб-интерфейс.  Изначально предлагается определиться с тем, какой массив вы хотите создать из дисков, установленных в NAS. Я построил RAID 1.

    Программа для входа на веб-интерфейс называется iSharing (тут автора скрутило в судорогах, интересно мне одному надоела буква i, добавленная спереди к чему-либо).

    После того как iSharing нашел ваш NAS открывается главный экран веб-интерфейса. Linux, как Linux.

    Захожу в MyCloud (хорошо, что не iMyCloud) — четыре стандартных папки Документы, Музыка, Фото, .

    В настройках все намного интереснее: тут есть адресная книга, приложения, информация и управление дисками, медиаплеер, разнообразные возможности кастомизации, втом числе и внешнего вида.
    Для интерфейса доступно 11 языков, среди которых есть великий и могучий русский язык.
    Если посмотреть информацию о дисках, то можно увидеть абсолютную правду — два диска по 3 Тб в массиве RAID 1 общим объёмом 3 Тб.

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

    FTP без проблем, работает, правда, если говорить начистоту я не пользуюсь этим протоколом дома. Так что, скриншот для галочки.

    Вот и информация о системе. Скрывать мне тут нечего, так что смотрите ).

    Для доступа к NAS из Интернет можно зарегистрировать имя на сайте myisharing.com и  коннектиться с работы к домашней хранилке. Возможность назначить внешний IP отсутствует, или, по крайней мере, я ее не нашел. На QNAP она есть и очень легко настраивается.

    Мастер закачек имеет одну очень неприятную особенность — он понимает только http адреса. Если вы захотите качать торренты, необходимо искать и ставить дополнительные программы.
    Итак, вроде о девайсе все. Пожалуюсь еще на систему обновления программного обеспечения. Эта нетривиальная, как выяснилось, задача под силу только самым настойчивым пользователям. Автоматическое обновление тупо не работает. Страница на английском языке на которую посылают для скачивания firmware не работает. И лишь при серфингу по немецкой версии сайта (благо ваш покорный слуга немного шпрехает на этом языке) удалось раздобыть новую прошивку. Аналогичная ситуация происходит и с дополнительными модулями для улучшения функционала. Теперь подведу итоги и расскажу о том, почему устройство не осталось жить у меня. Плюсы: невысокая цена (я нашел одно девайс в магазине примерно за 6400 рублей), компактные размеры, поддержка двух дисков, поддержка RAID 0/1. Минусы: отсутствие SATA III, отсутствие возможности присвоить внешний IP, отсутствие врожденной поддержки торрентов, отсутствие регулярных обновлений. Что здесь для меня критично? Ну, во-первых, конечно торренты. Причины думаю ясны всем. Во-вторых, внешний IP. У многих на работе стоят прокси, секущие всякие файлопомойки, но они бессильны перед простым обращением по IP к домашнему NAS. Эти две причины собственно и стали поводом для расставания с Fantec. Ругать и говорить, что вещь негодная не стану, для простого файлохранилища дома — она подойдет, но ИМХО не более того.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Модульного тестирования недостаточно. Нужна статическая типизация!

    Когда я работал над своей магистерской диссертацией, я пообещал себе, что опубликую ее в Интернете под свободной лицензией. Я получил степень, но, к сожалению, натолкнулся на одно из неписаных правил ВУЗов — когда вы тратите на интересующий вопрос много времени, он вам надоедает.
    Наконец, спустя год, я все-таки ее публикую.
    Для тех, кому лень знакомиться с моим полным трудом (в любом случае, 60 страниц текста это не так много для исследовательской работы, но это все же не мало), я предлагаю краткую версию статьи. Прошу заметить, что краткая версия не учитывает некоторые важные сведения, поэтому я прошу писать отзывы только о полной версии.

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

    Суть их рассуждений в следующем:
    1. Статической типизации недостаточно для выявления багов, поэтому необходимы модульные тесты;
    2. Статическая типизация становится лишней, так как у вас есть тесты;
    3. Из-за статической типизации некоторые корректные программы могут выдавать предупреждения на стадии компиляции.
    Несмотря на то, что я много раз слышал эти утверждения, я не мог найти им подтверждение. Поэтому я решил выяснить: действительно ли модульные тесты помогают устранить ошибки типизации. Также меня интересовал еще один вопрос: как часто разработчики используют конструкции языков с динамической типизацией, которые невозможно выразить в языках со статической.


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

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

    Критерии для динамического языка были следующими:
    1. этот язык должен быть динамически типизированным;
    2. язык должен поддерживать модульное тестирование;
    3. необходимо достаточное количество opensource-решений на этом языке;
    4. язык должен быть известным и иметь достаточное количество сторонников.
    Под эти критерии отлично подходит Python.

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

    Далее я выбрал четыре случайных проекта, которые предстояло транслировать с Python на Haskell: The Python NMEA Toolkit, MIDIUtil, GrapeFruit и PyFontInfo.

    The Python NMEA Toolkit
    Трансляция этого проекта привела к девяти ошибкам. Три из них возникли из-за неправильного типа входящих параметров, а остальные шесть из-за неверного использования API. Только одна ошибка типа была покрыта модульным тестом. С помощью статической типизации была исправлена одна ошибка, которая проявлялась при исполнении программы. От двух модульных тестов можно было бы избавиться, т.к. они служили лишь для проверки типов. Не обнаружилось ни одной динамической конструкции, которую нельзя было бы транслировать в статическую.

    MIDIUtil
    Трансляция MIDIUtil привела к выявлению двух ошибок. Одну из них можно было бы отследить с помощью теста. Еще одну устранила бы статическая типизация. Утилита MIDIUtil использует методы struct.pack и struct.unpack, которые не могут быть транслированы в язык Haskell напрямую, поскольку в них используется строка форматирования, содержащая типы аргументов и возвращаемого значения.
    Однако во всех случаях использования, форматирующие строки были жестко закодированы, так что код на Haskell мог использовать вместо них жёстко кодированные функции, не теряя выразительности. Если бы в MIDIUtil такие строки хранились в конфигурационном файле, то для её трансляции в язык со статической типизацией пришлось бы серьёзно поработать над архитектурой решения.

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

    PyFontInfo
    Перевод из PyFontInfo привел к выявлению 6 ошибок типов. Две ошибки при исполнении можно было бы устранить при использовании статической типизации. От одного теста можно было бы избавиться. PyFontInfo тоже использует struct.pack и struct.unpack, поэтому не может быть переведен в Haskell, но это ограничение можно обойти.

    Результаты
    Опыт показал, что все проекты без особого труда можно было бы транслировать на язык со статической типизацией, причем изменения были бы минимальными. Выяснилось, что модульное тестирование нельзя назвать адекватной заменой статической типизации. В ходе эксперимента обнаружилось 17 ошибок типизации, которые не были обнаружены тестами; но многие ошибки тестами все-таки покрывались.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Ты фрилансер и тебе надоело делить с индусами кусок хлеба?


    Тогда мы идем к вам!

    Если ты квалифицированный разработчик и тебе надоело терпеть на oDesk демпинг цен индусами, то новый сервис для тебя!

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

    Итак, сервис называется TopTal.



    Это еще одна площадка для фрилансеров. Такая же как oDesk, freelancer и elance. Но, есть одно отличие.
    Они проводят с вами 4 раунда собеседования перед тем как вы сможете принимать заказы!
    По пунктам:

    0. Вы регистрируетесь
    1. Через час или два вам в скайп стучится девушка и просит 5-10 минут вашего времени чтобы провести вводное интервью. На этом этапе она себе примерно записывает у себя кто вы такой и вы узнаете немножко о том кто они такие.
    2. Вам в почту падает ссылка на прохождение теста. Тест состоит из трех задач, которые нужно решить за 90 минут. После его прохождения результаты автоматически отсылаются в toptal и в случае успеха переходим к пункту 3.
    3. К вам стучится программист ( в моем случае это был старший инженер toptal) и просит вас решить две задачи при нем. Открываете screenshare в скайпе, свою среду разработки и пишете код :) В случае успешного прохождения переходим к п.4
    4. Вам на почту падает небольшое практическое задание, которое вы должны выполнить сами. После выполнения к вам снова стучится человек и просит вас показать что вы там натворили.
    5. В случае успешного прохождения предыдущих пунктов вам приходит письмо со ссылкой для доступа на toptal, где вы изменяете свой пароль и заполняете профиль. После полного заполнения профился и его модерации вам открывают полный доступ к сервису.

    Таким образом на получение этого доступа у меня ушла неделя. Зарегистрировался я там в прошлую пятницу, а закончил все процедуры буквально вчера.
    Что мы имеем в сухом остатке: 3 раунда нелегкого технического интервью на английском, котороые автоматически отсеивает львиную долю школьников, работающих за еду и других любителей демпинга.
    С сервисом работают крупные фирмы. Если хорошо зарекомендовать себя, то есть возможность найти себе работу вне сервиса у этих же клиентов (как впрочем и на любом другом фриланс-сайте).
    Три вида получения денег: банковский перевод, payoneer и paypal — большинству должно хватить.

    UPD: задачи удалены по просьбе TopTal

    Вот и все. Регистрируйтесь на TopTal!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    LG Optimus F5 — LTE в среднем сегменте

    Добрый день, хабрахабр!

    Сегодня я хочу рассказать вам о необычном «средняке» от LG — Optimus F5. Что в нём необычного? Да, наверное, ничего, кроме поддержки LTE сетей и приятного соотношения цена/функционал. Заинтересовались? :)

    kCeSN.jpg

    Железо
    Вопрос среднего сегмента и соотношения «цена/производительность» регулярно подвеграется пересмотру. Несколько лет назад LG Optimus One покорил бюджетный сегмент именно потому, что за свои деньги предлагал то, чего не было у остальных: нормальный экран с неплохим разрешением, вполне актуальное железо и неплохой корпус, удобный, простой и надёжный.

    qIxkX.jpg

    Что же установлено внутри LG Optimus F5?

    Процессор
    Qualcomm MSM82960: два ядра Krait на частоте до 1.5 ГГц
    Видеоядро
    Adreno 225
    Память
    RAM: 1ГБ LPDDR2, Flash: 8ГБ, слот под MicroSD до 32ГБ
    Камера
    5МП задняя, автофокус, без вспышки; 1.3 МП фронтальная
    Аккумулятор
    2150 мА*ч (такой же стоит в Optimus G)
    Дисплей
    4.3" IPS, qHD (960x540)
    Беспроводные интерфейсы
    WiFi, Bluetooth, NFC, 4G (LTE)

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

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

    Производительность
    Как я уже говорил, полтора года назад подобные железки вполне можно было встретить во флагманских и HI-End девайсах других компаний, а сегодня они в обычном смартфоне. Достаточно-ли железа для современных потребностей? На мой взгляд — да.

    Берём любой LG F5 в интернете, и убеждаемся, что в нём авторы говорят то же самое. Софт от LG неплохо оптимизирован и шустро бегает даже на куда менее производительном железе бюджетных моделей, так что о слове «тормозит» можно вообще не вспоминать. Бюджетным и MID-Range моделям от Samsung с их неподъёмным TouchWiz’ом такое и не снилось.

    Если кого-то интересуют результаты бенчмарков, то вот они:

    OgcbL1otZ.pngvzhnaE.png

    Дисплей
    Второй немаловажный фактор в смартфоне, который позиционируется одновременно как недорогой и практичный, — экран. В конце концов, другого способа взаимодействовать с девайсом у нас попросту нет. В F5 установлена IPS матрица с разрешением 960х540 точек. Для диагонали в 4.3 дюйма — вполне нормальный показатель. Конечно, есть модели с HD-разрешением на 4.3 дюймах экрана, но каких-либо ощутимых бонусов с переходом к 720p пользователь не получает, а вот стоимость такой матрицы, яркость подвестки и нагрузки на графическую подсистему вырастают ощутимо.

    VAp2a.jpg
    На фото яркость установлена ~ на 30% от максимальной.

    Углы обзора, цветопередача и яркость с контрастностью находятся на хорошем уровне. Цвета приятные, возможно, девайс чуть «желтит» (смаую малость!), но я бы не назвал это очень уж большим минусом — тёплая картинка не так сильно нагружает глаза, как холодные синие и голубые оттенки при заваленном балансе белого.

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

    Дизайн — прямое продолжение L-линейки, разве что пластик используется подороже, да общее оформление больше напоминает достаточно неплохие модельки в старшем сегменте.

    k6fNUS5DG.jpg

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

    G5vNub7Zm.jpg

    cX2MoT.jpg

    LTE
    Признаться, ощущения двоякие. С одной стороны — фича интересная, и в среднем сегменте её днём с огнём не сыщешь. С другой — карта покрытия пока оставляет желать лучшего… Но есть одно «но». Как только мы попадаем в зону действия сети четвертого поколения, интернет становится сложно отличить от хорошего Wi-Fi подключения. Скорость в районе 10 мегабит (бывает и выше), быстрый коннект, неплохая latency — в общем, может, в BattleField последний особо не поиграешь, но комфортно пользоваться интернетом, картами, просматривать или даже подключиться через TeamViewer для удалённого управления — это всегда пожалуйста. Тем более что остальная начинка позволяет вполне комфортно работать с другими приложениями, переключаться между несколькими задачами и вообще тенденция к «спуску» hi end фич в MID-сегмент не может не радовать. Сегодня — LTE, а завтра, глядишь, перестанут отстойные камеры в среднесегментники пихать. Кстати, о камере…

    Камера
    Модуль на 5 мегапикселей с автофокусом и без вспышки. С одной стороны — хорошо, что не 10 или 13 раздутых MPx’ов — меньше размер фоточек, а деталей всё равно было бы столько же. С другой — где вспышка, да и люди не поймут, почему не поставили хотя бы 8, которые есть в том же LG L7. Лично я камерой не занимался особенно: погода в Москве была отвратительная, снимать было нечего, да и ничего интересного она не предоставила бы в любом случае.

    GMwvB.jpg

    Зато ребята из Mobile Review гоняли девайс в хвост и гриву, и они точно так же характеризуют камеру как «среднюю по всем фронтам». Надеюсь, инженеры в LG дойдут-таки до камеры в ближайшем будущем, перепишут весь софт и найдут и покарают того, кто отвечал за камерный JPG. Вроде, не маленькие, оболочку написали толковую, девайсы делают неплохие, даже Goolge выбрал их в качестве поставщика для Nexus-смартфонов, а камерный софт никак не осилят.

    В общем, вот пара кадров моих, немного кадров из интернета, а там уж сами решайте, сколько валенков бросить в сторону отдела разработки софта для камер в офисе LG.

    Скрытый текст










    Конкуренты
    Если рассматривать только РСТ-аппараты, то в данном ценовом диапазоне (от 10 до 12 тысяч рублей), у F5 конкурентов, с одной стороны, много, а с другой — наверное и нет. В подобном ценовом диапазоне обитают hi end смартфоны двухлетней давности, некоторые mid range девайсы этого и прошлых годов, и все они по-своему «хороши». У кого впихнули HD-экран, и из-за этого смартфон превратился в лагалище. Где-то дохлая батарейка, где-то дурацкий корпус или, наоборот, экран так себе. Да и LTE есть у полутора землекопов.

    SlMqIRG.jpg

    Среди «серых» девайсов, конкуренция, конечно, обостряется, но давайте будем честными: представляете, сколько будет стоить «серый» F5? :)

    Вместо заключения
    У LG получился неплохой и крепкий среднячок: нормальные железки, неплохой экран, приятная оболочка, не заставляющая пользователя плакать кровавыми слезами из-за клоунского оформления, тормозов или странных решений. Плюс LTE. У Samsung’а, вон, не во всех четвёртых галактиках он есть. :) С автономностью также проблем не наблюдается — железо не самое прожорливое, а аккумулятор достался от куда более «заряженного» Optimus G.

    Без минусов не обошлось: так себе камера, нет вспышки (за что вспышку-то?!), глянцевый задник через год превратится в царапанный глянцевый задник. Скучаю по крышкам в стиле Galaxy S II — из прочного, гибкого и рифлёного пластика, без каких-либо намёков на пошлый глянец.

    angzsuU.jpg

    Если принять во внимание цену устройства и все предлагаемые им фичи — я бы поставил 4 балла из 5 возможных. Матовый корпус + вспышка — и были бы все 6 из 5. Простой, быстрый, недорогой, с приятным экраном, да ещё и LTE умеет (а значит можно и к ноутбуку подключиться, в случае чего, и не страдать от «качества» 3G-сетей. Что ещё надо для счастья, если вы не готовы отдавать 20-30 тысяч за смартфон? :)

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [recovery mode] Phalcon S: Быстрая разработка на phalconphp

    Добрый день!

    Уважаемый читатель: данная статья не является примером идеального программирования на языке php и предоставленный инструмент может содержать в себе множество недоработок. Phalcon S сырой и выкладывается для поддержки, или осуждения разработки.


    Сегодня я хочу показать сообществу Phalcon System (Система Ястреб).

    Описание и предыстория

    Phalcon S — это зачаток мульти-модульной системы, для построения вэб-приложения. Phalcon S изначально был задуман для персонального использования 1-2 разработчиками. Phalcon S написан с использованием Phalconphp и представляет из себя мульти-модульное приложение. На данный момент содержится модуль панели администратора, который откровенно говоря не доделан. Все началось с того, что мне была нужна система микроблоггинга. Поиски того что нужно, не дали успехов. Так как я обладаю некими знаниями языка php, было задумано писать самому. Систему для блогов я поднял за 3 дня и в качестве админки к ней начал писать Phalcon S (в свободное от работы время). К сожалению модуль микроблоггинга в общий доступ выложить не могу.

    Архитектуру наглядно можно изобразить так:



    Каждый модуль это отдельное mvc приложение.

    В папке dev находится каркас-пример для разработки модуля Phalcon S.

    Краткая инструкция по разработке модуля.

    Большинство настроек приложения храниться в формате xml. При разработке модуля, необходимо создать папку module_name/config/xml с настройками вашего модуля. Также необходимо разместить schema.sql и schema_drop.sql в папке module_name/config для создания таблиц в бд и соответственно удаления при деинсталяции модуля.

    Пример настройки роутинга:

    <code class="xml"><?xml version="1.0" encoding="UTF-8"?>
    <routes>
        <route name="pnews" url="/pnews" module="pnews" controller="pnews" action="index"/>
        <route name="pnews" url="/pnews/administrationpnews" module="pnews" controller="administrationpnews" action="index"/>
        <route name="pnews" url="/pnews/administrationpnews/add" module="pnews" controller="administrationpnews" action="add"/>
        <route name="pnews" url="/pnews/administrationpnews/delete/{item_id}/{page_number}" module="pnews" controller="administrationpnews" action="delete"/>
    </routes>
    </code>

    Пример настройки модуля (для регистрации его в системе):

    <code class="xml"><?xml version="1.0" encoding="UTF-8"?>
    <modules>
        <module name="pnews" className="P\Pnews\Module" path="../apps/modules/pnews/Module.php"/>
    </modules>
    
    </code>

    Остальные примеры можно найти тут Phalcon-S / dev / pnews / config / xml.
    Также необходимо знать, что ресурсы для ACL разделяются на модуль и контроллер. По умолчанию доступ ко всем ресурсам модуля, закрыт для всех пользователей. Allow нужно также добавить в настройках вашего модуля. Если вашему модулю нужны ресурсы css, images, js то разместите их в module_name/ext/module_name и при установке они будут перемешены в public/ext/module_name (это надо учитывать при прописывании путей к ресурсам).

    Верстка:
    Вьюшка вашего модуля должна содержать:

    <code class="php"><?php
    require_once $_SERVER['DOCUMENT_ROOT'] . '/templates/header.phtml';
    ?>
    
    
    <?php
    require_once $_SERVER['DOCUMENT_ROOT'] . '/templates/footer.phtml';
    ?>
    </code>

    если это контроллер для пользователей и:

    <code class="php"><?php
    require_once $_SERVER['DOCUMENT_ROOT'] . '/templates/admin-templates/header.phtml';
    ?>
    
    
    <?php
    require_once $_SERVER['DOCUMENT_ROOT'] . '/templates/admin-templates/footer.phtml';
    ?>
    </code>

    если это контроллер панели администрирования.

    github github.com/abasov90/Phalcon-S
    phalconphp phalconphp.com/en/
    phalconphp в по русски docs.phalconphp.ru/ru/latest/


    Phalcon S заслужил жизнь?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 65 человек. Воздержалось 45 человек.


    Удали это и забудь как страшный сон. (просьба обосновывать)



    Заслужил, продолжайте работу.


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Типичные уязвимости на сайтах, со статистикой

    Этот топик будет посвящен:
    • статистике встречаемости уязвимостей
    • реакции администрации(скорости и адекватности)
    • опасности
    и всяческим другим факторам. Будут приведены примеры.


    Что послужило толчком

    Пост можно начать так: «дело было вечером, делать было нечего». Или: «Навеяли былые успехи(прошлый топик вышел в плюс)».
    Одним словом, делать мне летом решительно нечего. А поэтому, пока потихоньку пилится мой прошлый проект(хабрасканер), я подумал быстренько набросать следующий пост. Кратенькое содержание уже есть выше. Разберем его(пост в смысле).

    Очень важно: все данные, приведенные в топике, достаточно примерны. Я проверил больше 1000 сайтов, около 200 оказались уязвимыми.

    Процесс поиска
    Кстати кому интересно, сайты были найдены совершенно случайным образом и проверены буквально в ручную.
    Поиском для меня занимался гугл. Я написал небольшой питон-скрипт, который вводил поисковый запрос(изначально взят был список запросов) и нажимал «Мне повезет!», а затем копировал эти данные в текстовичек, который я потом использовал для пентестинга.
    Кстати говоря, запросов было 1322, а значит и сайтов столько же. Отсюда можно посчитать, что уязвимых из них около 15%.

    Общая статистика
    image

    Уязвимый модуль
    image

    Вид уязвимости
    image
    Я должен пояснить, что HTMLBUG = изменение вида html с помощью какой-то формы, но без XSS(все-таки теги фильтруются).

    Примеры

    Я, опять же, просто обязан сказать здесь, что действительных примеров не будет. Это может быть попросту опасно, для исследованного сайта.
    А вот почему.
    image
    Здесь в «Не решено» входит и «Не ответили».

    Кроме того, в большей части проектов ко мне обращались грубо, пренебрежительно и даже угрожали…
    Это выглядет как-то так.
    Слова в гистограмме исковерканы намеренно, чтобы хоть как-то смягчить мои подсчеты.
    image
    Остальные либо не ответили, либо отделались сухим «Спасибо.»

    Отдельно хочется выделить работников интернет-магазина kronya.ru, мало того, что мне ответили в течение 15 минут(в пятницу-то), так еще и решены ВСЕ мои претензии были в течение часа.
    Кроме того, выделяю пользователя art_karetnikov, его сайт был проверен мной случано, и, к моему сожелению, и к всеобщей радости, вовсе не содержал проверяемых мной ошибок.

    А теперь наконец-то к примерам.
    Приведу пару-тройку примеров. Я думаю большая часть пользователей хабра умеет искать и использовать XSS, поэтому об этом кратко.
    http://******************d=%22%3E%3Cscript%3Ealert%280%29%3C%2Fscript%3E

    js, выводящий алерт. ">
    image
    (Окно уже закрыто) То есть здесь и XSS и странности с дизом. (ну странности с html наблюдаются всегда там, где получилось пробиться через input, поэтому я больше не буду их связывать между собой).

    На одном из сайтов встретилась форма, после которой ее содержимое присутствовало на сайте аж 5(!) раз. И выглядело как-то так.
    image
    image

    Неимоверное количество не фильтрованных запросов нашел я на просторах интернета.
    Больше всего мне понравился этот. Кстати расположен на крупном сайте одного московского магазина.
    image
    Всего-то ковычка в одном правильном поле. На этом сайте мне так и не ответили…

    Решения проблем
    По большей части, все эти уязвимости встречены на сайтах с фреймворками(найдены документации в корневых папках) или с (найдены признаки использования©). Поэтому путь решения прост как валенок. Переключить тумблер фильтрации в положение ON. Или дописать где-то 2 слова…

    К чему все это?

    Я надеюсь данный топик сможет:
    • Заставить пользователей быть внимательнее к ссылкам.
    • Админов быть внимательнее к своим творениям.
    • Менеджеров быть добрее к тем, с кем они общаются.
    • Программистов быть адекватнее и понимать, когда им пытаются помочь, а не обгадить(да простит меня хабрасообщество за это слово).

    P.S. В заключение, хочется сказать:
    «Дорогие хабровчане, мне, бесспорно, нравится проверять сайты на уязвимости и узнавать что-то новое для себя.»
    Если кому-то интересно, я мог бы проверить ваши сайты, а затем дополнить список с указанием конкретных примеров(конкретики не хватает, я думаю), естественно с вашего разрешения и, конечно же, после исправления.

    P.S.S. Я надеюсь моя статья будет полезным чтением для кого-то. Кому-то послужит уроком, или руководством к действию(я надеюсь админам, а не хакерам). И вообще, я надеюсь статья будет достойна habra.

    UPD.
    Привет анонимным минусовальщикам! (попросил бы комментировать)
    UPD2.
    Скрины реальных примеров, скрины переписки с админами(естественно подзатертые), и кругляши вместо гистограмм сделаю попозже. (нужно все это подготовить)


    Нужно ли больше примеров?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 290 человек. Воздержалось 64 человека.


    Нужно больше примеров с конкретными сайтами



    Достаточно фактической информации со скриншотов


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Строковая интерполяция. Сказка-быль

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

    Совершенно случайно я превратился из питониста в JS-разработчика, и на мою хрупкую детскую психику обрушился непосильный груз вещей, которых в JS нет. Например, нет удобного форматирования строк. На питоне можно написать:
    <code class="python">'hello, %(thing)s' % {'thing': 'world'}
    </code>
    Или вот так:
    <code class="python">'hello, {thing}'.format(**{'thing': 'world'})
    </code>


    Ближайший аналог в JS — конкатенация (
    operator +), которая очень плохо масштабируется с увеличением длины строки, да еще и выглядит безобразно до предела:
    <code class="javascript">'<div class="input-append"><input type="text" name="username" '+ 'id="signup_username" placeholder="'+placeholder+'"><input '+ 'type="hidden" name="password" value="'+generated+'"><button '+ ... </code>По возможности хотелось бы этого избежать.

    Jeremy Ashkenas, когда разрабатывал CoffeeScript, также обратил на эту особенность JS внимание, и случайно диалект PHP:
    <code class="coffeescript">"hello, #{document.cookie}" </code>Это тоже плохо, к тому же работает только для строковых литералов, загрузить шаблон из файла не получится.

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

    Поиск решения

    Обычно в таких случаях используют готовые библиотеки, более того, в NPM по слову template находится более двух тысяч пакетов.

    В самом деле, mustache или lodash (underscore.js) работают превосходно, но… очень медленно: 10-20 мкс на одну подстановку. Не предел мечтаний ни в коем случае, особенно когда «продвинутый» функционал вроде циклов и фильтров совершенно не нужен.

    А конкатенация, хоть и выглядит страшно, как звериный оскал коллективизма, работает все-таки в 10-30 раз быстрее. Таким образом, мы добавляем к постановке задачи:
    – транслируется в конкатенацию
    – и работает очень быстро
    Вот теперь по этой спецификации можно изобретать велосипед. Because why not.

    Что получилось

    У меня получилась вот такая штука: Ruby-like simple string interpolation (GitHub)

    В ней 9 строк кода, и она выполняет миллион триста тысяч подстановок в секунду (около 0,77 мкс на подстановку) на той же машине, где mustache делает 130 тысяч, а lodash/underscore 45 тысяч подстановок в секунду.
    <code class="javascript">var hello = fmt('hello, #{thing}') hello({thing: 'world'}) // -> hello, world </code>Вывод: за счет отказа от сложных функций шаблонизатора (циклы, условные выражения) было достигнуто ускорение в 10-30 раз по сравнению с популярными библиотеками, не прибегая к выполнению произвольного кода в шаблоне.

    Rssi.js можно установить из npm очевидной командой npm install rssi
    , поддерживается также Bower (
    bower install rssi
    ); на стороне клиента можно использовать AMD (RequireJS), а можно не использовать.



    Спасибо за прочитывание этого не очень связного текста! Пишите патчи, господа хорошие, и до новых встреч.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Переход с bootstrap 2 на bootstrap 3



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

    На днях вышла третья версия этого замечательного фреймворка, и, естественно, сразу захотелось посмотреть, как будут выглядеть сделанные на второй версии проекты, если просто поменять 2-ю на 3-ю. Оказалось что никак. Всё расползлось, разъехалось и кое-что перестало работать.

    После чего захотелось всё быстренько поправить. И вот, что из этого получилось, читаем дальше.

    Итак, первое нововведение — новый bootstrap не переопределяет стили элементов по-умолчанию, как это было раньше. С одной стороны, это, в принципе, правильно, потому что у него в стилях было куча
    !iportant 
    и он навешивался на практически все теги, поэтому, если какой то input казался чересчур высоким, то приходилось переопределять и не всегда это было удобно.

    Но, скорее всего, именно за эту особенность bootstrap многие и полюбили: без лишних телодвижений — подключил библиотечку и страница преобразилась.

    Теперь всё с точностью до наоборот: никакой самодеятельности, хочется красивенький
    input
    с синей подсветкой, — нужно прописать в нем соответствующий класс.

    <code class="html"><input class="form-control" type="text"/>
    </code>

    Нужен стильный заголовок страницы, оборачиваем его так:

    <code class="html"><div class="page-header">
      <h1>Блог Васи <small>Только умные мысли</small></h1>
    </div>
    </code>

    Кнопки
    Убран класс
    .btn-inverse
    . Теперь придётся выбирать ему замену или писать что-то своё.

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

    Классы, отвечающие за размеры кнопок, полей ввода и
    well
    -ов, обрели более лаконичные названия. Например, вместо
    btn-small
    стало
    btn-sm
    :

    <code class="html"><input class="btn btn-default btn-sm" type="submit"/>
    <span class="well well-lg"></span>
    </code>

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

    Темы
    Теперь в бутстрапе появилось такое понятие как темы. Сразу в комплекте идёт файл
    bootstrap-theme.css
    , который незначительно переопределяет внешний вид. Его можно использовать как основу для создания собственных тем, хотя, нужно признать, что он пока далеко не полно покрывает все визуальные стили. Созданием собственной темы можно заняться и с помощью веб-интерфейса на сайте фреймворка, где все стили удобно сгруппированы.

    В предложенной же «теме по-умолчанию» на первый взгляд не понравилось то, что кнопки при наведении практически никак не реагируют, в то же время, без темы
    .btn-default
    , можно сказать, вообще «никакого цвета». К счастью, это легко переопределяется в
    bootstrap-theme.css


    <code class="css">/* Переопределяем цвет кнопки */
    .btn-default {
      text-shadow: 0 1px 0 #fff;
      background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#e6e6e6));
      background-image: -webkit-linear-gradient(top, #ffffff, 0%, #e6e6e6, 100%);
      background-image: -moz-linear-gradient(top, #ffffff 0%, #e6e6e6 100%);
      background-image: linear-gradient(to bottom, #ffffff 0%, #e6e6e6 100%);
      background-repeat: repeat-x;
      border-color: #e0e0e0;
      border-color: #ccc;
      filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
    }
    /* Переопределяем цвет кнопки при наведении */
    .btn-default:hover {
        background-color: gray !important;
        background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(gray));
        background-image: -webkit-linear-gradient(top, #ffffff, 0%, gray, 100%);
        background-image: -moz-linear-gradient(top, #ffffff 0%, gray 100%);
        background-image: linear-gradient(to bottom, #ffffff 0%, gray 100%);
        border-radius:3px;
    }
    </code>

    Тулбары
    Тут тоже все немного усложнили. Вместо рабочего старого варианта:

    <code class="html"><div class="navbar navbar-fixed-top navbar-inverse">
        <div class="navbar-inner">
            <div class="container">
                <a href="/" class="pull-left navbar-brand">Название</a>
                <ul class="nav pull-left">
                </ul>
            </div>
        </div>
    </div>
    </code>

    вот такой новый

    <code class="html"><div class="navbar navbar-fixed-top navbar-inverse">
        <div class="navbar-inner">
            <div class="container">
                    <a href="/" class="pull-left navbar-brand">Название</a>
                    <ul class="nav navbar-nav pull-left">
                     </ul>
                </div>
            </div>
    </div>
    </code>

    Обратите внимание на класс .navbar-nav, который теперь должен сопровождать класс .nav

    Диалоги
    Диалоги теперь тоже усложнились. Было:

    <code class="html"><div class="modal hide fade " style="width:400px; margin-left:-200px; z-index:1000000;">
          <div class="modal-header">
               <button class="close" data-dismiss="modal">?</button><h3>Галерея</h3>
          </div>
          <div class="modal-body" style="width:380px; height:250px;"></div>
           <div class="modal-footer"><div class="btn-group">
                 <span class="btn yes btn-primary" data-dismiss="modal">Вставить</span>
                 <span class="btn cancel btn-danger" data-dismiss="modal">Закрыть</span>
           </div>
           </div>
    </div>
    </code>

    Стало:
    <code class="html"><div class="modal">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button class="close" data-dismiss="modal">?</button>
                    <h3 class="modal-title">Вставка кода</h3>
                </div>
                <div class="modal-body"></div>
                <div class="modal-footer">
                    <div class="btn-group">
                        <span class="btn yes btn-primary" data-dismiss="modal">Вставить</span>
                        <span class="btn cancel btn-danger" data-dismiss="modal">Закрыть</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    </code>

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

    Сетка
    Сетку основательно переделали. Наверно, это самое существенное изменение в фреймворке, обнаружив которое, в некоторых проектах, можно только недоумённо развести руками — больше нет фиксированных размеров, признаётся только динамическая ширина столбцов. Классы разметки, отвечающие за ширину колонок, .span2, .span3 и т.д. заменены на соответствующие .col-md-2, .col-md-3…

    Картинки
    Больше нет класса img-polaroid. Вместо него можно использовать img-thumbnail

    Иконки
    Иконки самого bootstrap теперь реализованы шрифтом, а не спрайтами. Вместе с этим изменены и названия классов, которые теперь все придётся заменить.

    <code class="html"><i class="icon-pencil"></i> 
    </code>

    надо писать

    <code class="html"><i class="glyphicon glyphicon-pencil"></i> 
    </code>

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

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


    Пожалуй, это все, что бросилось в глаза в первом приближении.

    Полезные
    Справка отличий при миграции (англ.)
    Веб-интерфейс настройки стилей bootstrap
    Автоматический преобразователь разметки с 2-й на 3-ю версию bootstrap (спасибо muhas за ссылку)

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Следим за голосованием на «Россия 10»

    Как и многие россияне, в последнее время я каждый день захожу проголосовать на сайт 10russia.ru. Если кто не в курсе, Россия 10 — всероссийский проект, в рамках которого каждый может проголосовать за свой любимый географический или архитектурный объект в России. Задача проекта – выбор десяти новых визуальных символов России.
    Мне показались странными цифры в ТОП2 в голосовании, и я решил посмотреть, как они меняются. Было мало времени, и на скорую руку написал маленький парсер, который сохраняет раз в 2-3 секунды данные по количеству голосов на сайте и смс. Для отображения этих данных создал сайт (За основу был взят дизайн и основа графика отсюда habrahabr.ru/post/176547/. Надеюсь, автор будет не против ). Денег не хотелось тратить, а в распоряжении был только личный слабенький VDS, который бы быстро лёг, если бы данные генерировались динамически. Поэтому решено было обойтись статическим html и генерацией по крону json файлов. Интересно будет посмотреть, какую нагрузку выдержит VDS без изменения текущей конфигурации (CPU 300MHz, RAM 128 Mb), учитывая, что там крутится два небольших сервиса и один малопосещаемый сайт. В конце голосования выложу, если кому надо, все полученные данные голосования.

    Листинг парсера
    <code class=""><?php
    set_time_limit(0);
    function handleError($errno, $errstr, $errfile, $errline, array $errcontext) {
        if (0 === error_reporting()) {
            return false;
        }
        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
    }
    set_error_handler('handleError');
    mysql_connect('localhost', 'login', 'password');
    mysql_select_db('10russia');
    
    function addNewData($html, $key) {
        $site = $sms = 0;
        if( preg_match('/<span id="count_votes_site">([^<]+)/iu', $html, $match) ) {
            $site = (int)str_replace(' ', '', $match[1]);
        }
        if( preg_match('/<span id="count_votes_sms">([^<]+)/iu', $html, $match) ) {
            $sms = (int)str_replace(' ', '', $match[1]);
        }
        if($site && $sms) {
            $all = $sms + $site;
            mysql_query("INSERT INTO stat(`key`, sms, site, `all`) VALUES('$key', $sms, $site, $all)");
        }
    }
    
    $urls = array(
        'object_31' => 'http://10russia.ru/object_31',
        'object_61' => 'http://10russia.ru/object_61'
    );
    while(true) {
        foreach($urls as $key => $url) {
            try {
                $result = file_get_contents($url);
                addNewData($result, $key);
                sleep(1);
            } catch(Exception $e) {}
        }
    }
    </code>

    Листинг скрипта для создания по крону json файлов
    <code class="php"><?php
    mysql_connect('localhost', 'login', 'password');
    mysql_select_db('10russia');
    
    $keys = array(
        'object_31' => 'object31.json',
        'object_61' => 'object61.json'
    );
    
    foreach($keys as $key => $file) {
        $filename = dirname(__FILE__) . '/' . $file . '.tmp';
        $fLink = fopen($filename, 'w');
        if($fLink) {
            $result = mysql_query("SELECT `date`, `all` FROM stat WHERE `key`='$key' ORDER BY id ASC");
            fwrite($fLink, "[\n");
            $row = mysql_fetch_assoc($result);
            $first = true;
            do {
                $str = '';
                if(!$first){
                    $str = ",";
                } else {
                    $first = false;
                }
                fwrite($fLink, $str . '['.strtotime($row['date']) . "000,{$row['all']}]" );
            } while($row = mysql_fetch_assoc($result));
            fwrite($fLink, "]");
            fclose($fLink);
            rename($filename, dirname(__FILE__) . '/' . $file);
        }
    }
    </code>
    Интересный момент – я сначала генерирую .tmp файл, а потом им перезаписываю файл сгенерированный час назад, тем самым можно избежать ситуации, когда файл не существует или не полностью сгенерирован.

    Интересные моменты на графиках
    Максимальный прирост за 30 минут
    Максимальный прирост за 30 минут

    Общая динамика за всё время мониторинга
    Общая динамика за всё время мониторинга

    ВГТРК
    Я надеюсь что не создал для вас больших проблем, учитывая большую популярность проекта, вы, думаю, были готовы к большому потоку посетителей. Кстати, если кто ищет в Москве работу системного администратора, то создатели сайта ищут себе сотрудников, уже не совсем оригинальным, но редким способом:
    Работа


    Посмотреть, что у меня получилось, ознакомиться с детальной статистикой голосования и сделать выводы: http://10russia.miningdata.ru/

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Первое исследование NASA о возможности пилотируемого полета к Марсу на корабле с ядерным двигателем (1960)



    В ноябре далекого 1957 года — в том же самом месяце, когда Советский Союз запустил в космос собачку Лайку на борту 508-килограммового Спутника 2 — около 20 инженеров Исследовательского Центра Льюиса начали исследование возможности использования ядерных, ионных и ракетных двигателей для межпланетных перелетов. 1 октября 1958 года, сразу после образования NASA, центр Льюиса попал под эгиду Агентства, а уже в апреле 1959 года его специалисты отчитались о своей работе перед Конгрессом, попросив финансирование для исследований возможности полетов на Марс. Конгресс ответил согласием, дав добро на первое в США исследование, касавшееся пилотируемого полета на Марс на ядерном двигателе.

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


    Общий вид пилотируемого космического корабля. А — ядерный ракетный двигатель. B — центральный бак, C, D — кластеры баков жидкого водорода, E — отсек экипажа, F — Марсианский посадочный модуль, G — Земной посадочный модуль. Изображение NASA.

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

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

    Очевидно, что более короткий перелет на Марс потребуют, в целом, большее количество топлива (по плану исследователей, это должен быть жидкой водород), чем более долгий [например, с использованием гравитации других небесных тел для ускорения, — прим.пер.]. С другой стороны, в случае медленного полета пришлось бы брать с собой большее количество груза — необходимого экипажу воздуха, воды и еды. В конечном итоге, исследователи остановились на миссии продолжительностью в 420 дней, включая 40-дневный «период ожидания» на орбите Марса. В чисто аналитических целях они даже выбрали дату старта — 1971 год — однако подчеркнули, что «это не означает, что на это время будут запланированы какие-либо реальные полеты». В качестве точки старта была выбрана 480-километровая орбита вокруг Земли.

    Оптимальной датой запуска было выбрано 19 мая 1971 года — когда дельта-V, необходимое для перелета от Земли к Марсу составило бы 19.78 километров в секунду — при учете, что ускорение и торможение проходили бы полностью за счет тяги ядерного двигателя.[1] При данном сценарии, необходимая величина Дельта-V была бы достигнута за счет нагревания рабочего тела двигателя от реактора, и выбрасывании его из ракетного сопла. Очевидно, таким образом, что чем большее дельта-V необходимо было получить, тем большим было необходимое количество рабочего тела (жидкого водорода). Для сравнения, для миссии продолжительностью 300 дней необходимое значение дельта-V составило бы 26,55 километров в секунду, а для 950-дневного полета — всего лишь 12,39 километров в секунду.

    [1] [Под дельта-V понимают разницу в скорости, которой необходимо достичь для успешного проведения маневра. При этом, направление вектора скорости не учитывается, то есть если космическому кораблю нужно ускориться с 0 до 1 км/с, а затем замедлиться снова до 0, то дельта-V составит 2 км/с., прим.пер.]

    Авторы показали, что для снижения полетной скорости аппарата прекрасно подходит маневр торможения об атмосферу, что поможет сократить массу корабля [на величину массы рабочего тела, которое иначе понадобилось бы для торможения двигателем, — прим.пер.] В теории, если торможение об атмосферу было бы применено как на подлете к Марсу, так и при возвращении на Землю, величину дельта-V, которую необходимо было бы получить с помощью двигателя, можно было бы сократить вдвое.

    Однако эти цифры верны лишь если предположить что термощит, который должен был защитить экипаж от нагрева корабля при проходе через атмосферу, не имел бы массы. На практике же маневр торможения затруднялся еще и тем, что помимо массы самого корабля пришлось бы затормаживать и массу находящегося в его баках водорода, необходимого для возвращения на Землю. При этом жидкий водород имеет весьма малую плотность, поэтому для его хранения понадобились бы большие резервуары. Учитывая это, расчетный вес термощита, который мог бы защитить и отсек экипажа и баки с топливом, получался настолько большим, что маневр торможения об атмосферу Марса позволял бы сэкономить уже на 25% массы, а всего лишь около 3%.

    Из-за этих сложностей исследователи пришли к выводу, что целесообразнее было бы применять торможение об атмосферу только при возвращении на Землю. Их 15-тонный, 7-метровый Земной Спускаемый Модуль должен был иметь термощит, который при входе в атмосферу сгорал бы, унося таким образом излишек тепла (такая конструкция щита использовалась на корабля Восток, Восход, Gemini и Apollo, и продолжает использоваться до сих пор на Союзах и Shenzhou). При этом, во время торможения щит потерял бы до 10% собственной массы, а экипаж испытывал бы перегрузки вплоть до 8g. Расчеты показывали, что вес термощита в таком случае был бы в 6 раз меньше чем вес рабочего тела, необходимого для аналогичного торможения при помощи двигателя.

    Переходя к вопросу радиации, исследователи предупреждали, что «имеющиеся [на тот момент] знания в области вредного воздействия радиации нельзя считать исчерпывающими» [мягко говоря, — прим.пер.]. Они перечислили следующие факторы, влияние которых следовало рассмотреть: пояса Ван-Аллена вокруг Земли и Марса (на самом деле, у Марса нет радиационных поясов, но тогда об этом не знали), космическое излучение, солнечные вспышки и собственная радиоактивность реактора корабля.

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


    Изображение отсека для экипажа. A — высокозащищенное от радиации помещение, B — жилой отсек, C — грузовой отсек. Изображение NASA.

    Отсек экипажа — это легкозащищенный двухпалубный «барабан» общим объемом 118 кубических метров, который должен был предоставить около 4,645 квадратных метров площади на каждого члена экипажа («Нечто среднее между площадью, которая есть у старшин и у офицеров на подлодке», — говорится в докладе). В центре отсека находится высокозащищенный «сейф» объемом около 17 кубических метров. За исключением этого защищенного помещения, весь отсек экипажа (5 метров в высоту, 10 метров в диаметре [цифры не сходятся, но оставим это на совести авторов оригинала, — прим.пер.]) будет весить всего около 15 тонн. Члены экипажа будут находится в центральном защищенном отсеке во время прохождения поясов Ван-Аллена, операций с ядерным двигателем, а так же крупных солнечных вспышек. Спать экипаж тоже будет там, чтобы как можно сильнее снизить воздействие космической радиации. Исследователи также учли, что 15 тонн припасов, размещенных вокруг центрального отсека, послужат дополнительной защитой [видимо они посчитали, что еду защищать не надо, — при.пер.].

    Очевидно, конечно, что общая масса «щита», необходимого для центрального отсека, сильно зависит от того, какова максимальная величина радиации, допустимая для экипажа. При условии избежания крупных солнечных вспышек и допустимом уровне радиации в 100 Бэр, щита массой 23,5 тонны должно было быть достаточно. При максимальной допустимой дозе облучения в 50 Бэр и допустимости одной крупной солнечной вспышки, масса щита должна была бы составить уже 140 тонн. «Эти данные», — говорится в докладе, «подчеркивают важность изучения влияния и опасности космической радиации на человека».

    [Стоит отметить, что в этом вопросе исследователи были довольно оптимистичны. Английская википедия говорит, что 100 Бэр, полученные за достаточно небольшой промежуток времени (правда не уточняя что значит «достаточно небольшой») приведут к острой лучевой болезни и смерти в течение нескольких недель. Согласно русской википедии, ликвидаторы Чернобыльской аварии получили дозы облучения около 100 миллизивертов (при том, что «жители некоторых регионов Земли с повышенным естественным фоном получают дозы облучения, равные примерно 100—200 мЗв за 20 лет»). 1 зиверт (в 10 раз больше) равен как раз таки 100 БэР. Разумеется, в 60-х годах воздействие радиации человека было практически не изученным. Если у кого-нибудь есть более точная информация на эту тему, напишите, пожалуйста, в комментариях — прим.пер.]

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

    Исследователи подсчитали, что масса корабля для 420-дневного полета, с учетом дозы радиации в 100 Бэр, составит около 675 тонн на момент его предполагаемого запуска с Земной орбиты в 1971 году.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Представители Bitcoin Foundation провели встречу с государственными структурами США

    26 августа Bitcoin Foundation провели встречу для представителей гос. структур. На мероприятии присутствовали представители ФБР, налогового управления, федеральной резервной системы, управления по контролю денежного обращения, федеральной корпорации по страхованию депозитов и представители секретной службы США. Как видите список достаточно велик.

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

    Стивен Худак, представитель подразделения по расследованию финансовых преступлений США(FinCEN), сказал, что это была самая обыкновенная Q&A встреча. По мнению FinCEN, все виртуальные валюты должны контролироваться и регулироваться финансовыми органами США, а данные о сделках с их участием подлежат раскрытию информации о платежах с целью предотвращения отмывания денег и других финансовых преступлений. Очевидно, что анонимность криптовалюты очень раздражает американское правительство и оно всячески пытается взять его под свой контроль. И если это у него получится, то смысл и интерес к такой валюте будет сведен к минимуму.

    Сразу после проведения мероприятия, на Mt.Gox было совершено операций примерно на 30.000 биткоинов, что всего за пару часов подняло стоимость валюты со 120$ до 133$ за еденицу.


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

    UPD: Кстати, не так давно правительство Германии тоже признала Биткоин в качестве средства оплаты. В Германии криптовалюта использовалась с целью ухода от выплаты 25% налога при совершении сделок. Планируется так же взимать налог с граждан, которые зарабатывают на покупке\продаже криптовалюты. Данный закон вступит в действие ближе к декабрю.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] OpenWRT, или что еще можно сделать со своим роутером

        Здравствуйте, на написание данной статьи меня натолкнула аналогичная, но в качестве сервера выступала Raspberry Pi. По моему мнению использовать эту маленькую, но при этом достаточно мощную платку в этих целях немного не целесообразно, у многих есть wi-fi роутер с USB портом, а следовательно зачем включать в розетку целый блок питания от компьютера давая при этом пускай и не большой, но все таки расход электроэнергии когда в розетку включено уже все что надо.
    В данной статье рассмотрим установку торрентокачалки на практический любой роутер с USB и поддержкой OpenWRT прошивки. В наличии у меня имеется Linksys E3000, но конкретной разницы в установке и настройке OpenWRT нет. Что нам для этого будет нужно:

    • Непосредственно роутер с разьемом USB, в идеале конечно с двумя.
    • Флешка/ USB HDD произвольного объема под Ваши нужды чем больше тем лучше.
    • Буквально пол часа свободного времени чтобы все поставить и настроить.
    • Прямые руки.


    Установка / настройка OpenWRT
        Прежде всего сразу оговорюсь что Вы все делаете на свой страх и риск, так как существует вероятность «окирпичивания» Вашего роутера. Проверяем есть ли Ваш роутер в списке поддерживаемых устройств, для этого заходим на сайт OpenWrt



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



        После этого переходим в вкладку «Downloads»



        Тут стоит выбрать какую ветку использовать стабильную (Attitude Adjustment) или соответственно «trunk» в папке snapshots, сразу замечу если Ваш роутер более менее новой модели, то скорее всего в стабильной ветке вы его не найдете.



        Переходим непосредственно к скачиванию прошивки.



        После того как прошивка скачалась переходим к прошивки Вашего роутера. Для этого необходимо зайти в его вэб-интерфейс который обычно располагается по адресу 192.168.1.1 или 192.168.0.1 в зависимости от производителя роутера. Подробнее по процессу прошивки и настройки Wi-Fi и всего остального для конкретного роутера можете обратится в Google, а то эта статься может растянуться до неприличных размеров, мы же остановимся именно на установке и настройке Transmission.

    Установка и настройка Transmission
         После прошивки роутера запускаем PuTTY если Ваша ОС Windows, если Linux то просто запускаете терминал. В поле адрес вбиваем 192.168.1.1 для PuTTY либо команду
    telnet 192.168.1.1
    для Linux. После успешного подключения переходим к установке / настройке пакетов.

        Перед скачиванием пакетов следует маленькое отступление. Так как в роутере физической памяти достаточно мало, колеблется от 4 до 16 мегабайт в зависимости от продвинутости и цены Вашего роутера, нам следует заранее побеспокоится о его увеличении. Ведь мы в любом случае собираемся подключать к нему флешку или жесткий диск так почему бы нам не сделать чтобы роутер грузился непосредственно с раздела на нашем носителе? Давайте сделаем это! Перед всеми манипуляциями с роутером нужно «разбить» Ваш HDD/флешку на несколько разделов.

    1. Раздел под своп (100-200 МБ будет достаточно) * при использовании HDD, при использовании флешки не рекомендуется, так как имеется хоть и большой но все таки ограниченный запас циклов перезаписи
    2. Раздел с которой будет грузится роутер (на Ваше усмотрение от 50 МБ и выше) с файловой системой Ext3 или Ext4 * Вот тут то нам и может пригодится вторая флешка, куда лучше разместить загрузочную область и область для хранения закачек на разных устройствах чтобы безболезненно извлекать ее для скидывания информации без выключения роутера.
    3. Раздел под Ваши загрузки / хранилище все оставшееся место желательно тоже в Ext3/4 если хотите периодический использовать носитель на компьютере то NTFS но приготовьтесь к периодическим ошибкам, так как Linux с этим типом ФС «дружит» довольно посредственно, так же дополнительно придется установить еще один пакет
      ntfs-3g
      .
        Это все конечно можно было сделать и на роутере, но на компьютере это все происходит гораздо быстрее и можно воспользоваться программами с графическим интерфейсом, а не просто командной строкой терминала, что для новичка значительно ускоряет процесс. Как все это проделать на Windows и Linux опять же можно посмотреть на Google по той же причине что и первое обращение к этому источнику.

        Приступим. Вводим последовательно команды в терминале

    opkg update
    opkg install block-mount kmod-usb-core kmod-usb2 kmod-usb-ohci kmod-usb-storage kmod-fs-ext4
    Этими командами мы обновили базу репозиториев на роутере и установили необходимые нам пакеты: модули ядра для поддержки USB и модули файловой системы

    block info

    И ищем наши разделы на флешке / HDD * Вы же не забыли подключить Вашу флешку / HDD к роутеру правда?

    mount /dev/sdaX /mnt
    mkdir /tmp/cproot
    mkdir /home
    mount --bind / /tmp/cproot
    tar -C /tmp/cproot -cvf —. | tar -C /mnt -xvf — sync; umount /mnt
    umount /tmp/cproot

    Здесь взамен
    sdaX
    надо выбрать тот раздел с которого мы собираемся производить загрузку в дальнейшем. Все остальные команды предназначены для копирования загрузочного раздела роутера на флешку / HDD.

    block detect > /etc/config/fstab

    Данная команда записывает все найденные разделы для автоматического подключения в файл
    /etc/config/fstab
    . Дальше нам надо немого подредактировать этот файл к виду:

    config 'global'
    option anon_swap '0'
    option anon_mount '0'
    option auto_swap '1'
    option auto_mount '1'
    option delay_root '0'
    option check_fs '0'

    config 'mount'
    option target '/'
    option uuid '7d3abfaf-493a-46bb-9730-1d793ecb9783'
    option enabled '1'

    config 'mount'
    option target '/home'
    option uuid '7d3abfaf-463a-46db-9730-1d793ecb4593'
    option enabled '1'

    config 'swap'
    option uuid '76d36596-5710-4b77-a3a7-02a66d469750'
    option enabled '1'

    Открываем данный файл для редактирования:

    vi /etc/config/fstab


    Как пользоваться данным редактором можно посмотреть тут или опять же обратится в Google.
    Перезагружаем роутер. Опять заходим в консоль и проверяем все ли правильно подмонтировалось:

    root@OpenWrt:~# df
    Filesystem 1K-blocks Used Available Use% Mounted on
    rootfs 2758072 118004 2501828 5% /
    /dev/root 2048 2048 0 100% /rom
    tmpfs 63340 76 63264 0% /tmp
    tmpfs 512 0 512 0% /dev
    /dev/sda1 2758072 118004 2501828 5% /

    Тут следует обратить внимание на то чтобы
    rootfs
    совпадал по параметрам с
    /dev/sda1
    , если это так то у нас все получилось. Переходим к следующему пункту.

    Установка torrent клиента Transmission.

    opkg update
    opkg install transmission-daemon transmission-cli transmission-web transmission-remote
    /etc/init.d/transmission enable

    Открываем файл настроек клиента и редактируем под свои нужды:

    vi /etc/config/transmission

    config transmission
    option enable 1 # непосредственно включает клиент
    option config_dir '/etc/transmission' # расположение фалов настроек клиента
    option alt_speed_down 50 # ограничение скорости
    option alt_speed_enabled false
    option alt_speed_time_begin 540
    option alt_speed_time_day 127
    option alt_speed_time_enabled false
    option alt_speed_time_end 1020
    option alt_speed_up 50
    option bind_address_ipv4 '0.0.0.0'
    option bind_address_ipv6 '::'
    option blocklist_enabled false
    option dht_enabled true
    option download_dir '/home/' # директория для загрузок
    option encryption 0 # шифрование
    option incomplete_dir '/home' # директория для не завершенных загрузок
    option incomplete_dir_enabled false # включение/выключение директории для незавершенных загрузок
    option lazy_bitfield_enabled true
    option lpd_enabled false
    option message_level 2
    option open_file_limit 32
    option peer_limit_global 240
    option peer_limit_per_torrent 60
    option peer_port 51413
    option peer_port_random_high 65535
    option peer_port_random_low 49152
    option peer_port_random_on_start false
    option peer_socket_tos 0
    option pex_enabled true
    option port_forwarding_enabled false
    option preallocation 1
    option proxy ""
    option proxy_auth_enabled false
    option proxy_auth_password ''
    option proxy_auth_username ''
    option proxy_enabled false
    option proxy_port 80
    option proxy_type 0
    option ratio_limit 2.0000
    option ratio_limit_enabled false
    option rename_partial_files true
    option rpc_authentication_required false
    option rpc_bind_address '0.0.0.0'
    option rpc_enabled true
    option rpc_password ''
    option rpc_port 9091
    option rpc_username ''
    option rpc_whitelist '127.0.0.1,192.168.1.*'
    option rpc_whitelist_enabled false
    option script_torrent_done_enabled false
    option script_torrent_done_filename ''
    option speed_limit_down 100
    option speed_limit_down_enabled false
    option speed_limit_up 40
    option speed_limit_up_enabled true
    option start_added_torrents false
    option trash_original_torrent_files false
    option umask 18
    option upload_slots_per_torrent 14
    option watch_dir_enabled false
    option watch_dir ''

    Запускаем и проверяем:

    /etc/init.d/transmission start

    Запускаем браузер и вводим 192.168.1.1:9091 если все работает то на этом все.

    Если данная статья кого то заинтересует готов так же рассказать о настройке «файлопомойки», поднятия VPN сервера, настройка IPTV на OpenWRT.

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

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Заовнил, вонзился, запилил: словарь IT-шника

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

    Про код и изменения




    Код добра – программный код, очевидно содержащий непоправимые улучшения.
    Котятоемкий код — очень некрасивое техническое решение. Выражение обязано своим происхождением предположению, что каждый раз, когда программист пишет строчку некрасивого кода, бог убивает котенка.
    Непоправимо улучшить – запилить годное, но не до конца проверенное изменение функционала. Синоним — необратимо улучшить.
    Мясной коммит (ковровый коммит) – правка, судя по количеству и характеру изменений, наверняка содержащая непоправимые улучшения.
    Тупач – очень срочная задача, результаты работ по которой должны попасть в бранч для выкатываемой версии. Образовано от to patch.
    Минорный тупач – задача горит – сильнее некуда, но уж очень мелкая.
    Глубокий ToDo Later — (отправить задачу в глубокий тудулейтер) статус задачи в таск-трекере отложена на неопределенный срок.
    Подпереть костылями – реализовать функциональность за счет непредусмотренного временного решения.
    Шрапнельные правки – огромное количество мелких правок по всему проекту, которые очень сложно оттестировать.
    Скриптюня — очень классный скрипт, экономит кучу времени, практически лучший друг оператора.

    Про баги




    Багло – баг обыкновенный. Багуша – более мягкий вариант, баглище – баг большой, сложный, страшный. Баглицо – скрытый баг; обычно баглицо закрадывается в код незаметно.
    Багополучно – до достижения необходимого эффекта.
    Какая-то хурма – синоним непонятного багла.
    Локализация всё сломала – необъяснимая проблема.
    Сайд-эффекты — нежелательные последствия небольшой доработки, разрушительные по своему действию.



    Про рабочие моменты




    Заовнить — забрать запрос к себе на решение.
    Вонзиться — начать делать.
    Повтыкать – заняться исследованием проблемы.
    Курить маны – читать документацию.
    Обчекать что-то об кого-то – убедиться, что ответственное лицо не против предлагаемого решения.
    Тамагочить – предельно настойчиво расспрашивать, узнавать информацию.
    в полях – работа в дата-центре.
    Параллизовать, параллизованый – распараллелить/распараллеленный процесс.
    Причаститься – принять участие в каком-нибудь процессе (скажем, собрании). Пример употребления: Причастился к расследованию отваливающегося света.
    Запилить – сделать. Синоним: зарешать. Запилить можно стремительно и яростно.
    Покуэить – проверить, проконтролировать качество.
    Выкатить – выложить код на живое.
    Живое – продакшн, то, что видит непосредственно пользователь.
    Накатить [патч], исходом может быть либо сукесс (от success), либо факап.
    Отжечь – сделать опасную возможно деструктивную операцию. Пример употребления: Отжечь по живому.
    Накёрнилась – падение системы (от kernel), в общем случае — падение/кривота/куча багуш.
    Откатить – вернуть предыдущую версию.
    Разимплементить – фича привнесла баг в логику и ее надо выпилить.
    Свайпить – привести к состоянию по умолчанию.
    Конец — возможность использовать некий функционал, обычно это часть API.
    Дергать конец — использовать возможность доступа к некоему функционалу API.

    Про магию и необъяснимое




    Автомагически – что-то хорошее, происходящее автоматически.
    Метод пристального взгляда – способ отладки программы без использования отладчика или оптимизации без использования профилировщика.
    Был испуган – редко используемое объяснение для необъяснимого креатива в коде.

    Про коллег




    CSS-программист – переходящая штатная должность для разработки особо сложных задач, к примеру, исправления опечаток или изменения цвета шрифта.
    Тостер – тестировщик. Тестостеровщик – мужчина-тестировщик.
    Поросята – новички, находящиеся на испытательном сроке.
    Котята – новички, прошедшие испытательный срок.
    Котаны – сотрудники со стажем.
    Говорить без камер — выйти на перекур.

    Про внутреннюю терминологию




    Поправить здоровье – починить Здоровье Mail.Ru. А также «Как ваше здоровье?» — вопрос менеджеру проекта Здоровье.
    Починить/сделать/раскатать детей – совершить соответствующие действия с сервисом Дети Mail.Ru. А также «Это Вася, он делает детей» – представление сотрудника проекта Дети.
    Ссылка от Илая – ссылка в локальном чате, которая содержит непривлекательный контент. Такую ссылку лучше не открывать. Термин назван по имени сотрудника, который постит такие .
    Таск от Ромы – неприоритетная задача, при выполнении которой поросята и котята забывают про основные задачи.

    Про игровое

    Неписи – NPC, компьютерные персонажи, они изъясняются либо баблами (speech bubble), либо куесами (cue).
    Ушатать, банануть – заблокировать игровой аккаунт.
    Флагнуть – присвоить отличительный флаг запросу.
    Зерг – множество запросов, поступающих за короткое время.
    В паблике – логин и пароль от игрового аккаунта опубликованы на публичном ресурсе, в результате чего возникает радуга.
    Радуга, светомузыка, радость эпилептика – перебор множества случайных цветов, каждый из которых отвечает за визуальную подсветку своего интернет-провайдера в логах сессий игрового аккаунта. Такое явление возникает в тех случаях, когда множество (от 10 до бесконечности) игроков с разных регионов страны пытаются залогиниться на один аккаунт. Пример: http://bit.ly/1bO7n68 (IP сгенерированы случайным образом, совпадений с реальными логами быть не может).
    Пошарить – передать игровой аккаунт другому игроку на неопределенное время.
    Улитки – улики (доказательная база на блокировку аккаунта).
    Авокадо – адвокат (при угрозах решить текущую проблему пользователя через суп).
    Суп – суд.
    ДУБАНАК – (do ban acc) – название страницы в инструментарии, отвечающей за блокировку аккаунта.
    Это тебе не dxdiag туда-сюда – сложная задача, в отличие от разбора множества файлов dxdiag, присланных пользователями.
    Плизду – вежливая просьба в GPT, от please do.

    Про админское




    Тазик – сервер.
    Дырка – открытый порт.
    Просверлить (проковырять) дырку – открыть порт.
    Плевалка – сервер, отдающий небольшие куски данных, например, код загрузки баннеров.
    Соска – сетевой интерфейс.
    Аутхи – серверы авторизации (auth).
    Стораджа – серверы с файлами.
    Черный сторадж – по преданию, сервер, который уводил с собой всю стойку серверов (из-за проблем с БП). В настоящее время – любой сервер с проблемами питания.
    Задебинить, загентать – загрузить сервер с rescue image. Производные от дистрибутивов, на основе которых этот образ сделан.
    Накудрить – подготовить свежий тазик для продакшена.
    Заэсэсхаться (заSSHаться) – подключиться к серверу по протоколу SSH.
    Blackout, он же Черный $День_недели – авария электропитания в ДЦ.
    Нопинг – определение сервера, который не отвечает по icmp. Производное от no ping.

    Про эмоциональное состояние




    Баттхерт (бугурт) – крайняя степень недовольства, доставляющая физические страдания.
    Стул сгорел – результат баттхерта.
    Бизнес-гель – вазелин.
    Халк ломать!!! — боевой клич программиста, готовящегося к неминуемой каре за то, как его работа отразилась в системе continuous integration.
    По-братски — волшебное слово. Пример употребления: Метнись за кофе, по-братски.
    No pasaran no rebootan! — боевой клич
    Грешновато – оценочное суждение о рабочей операции, часто — ответ на вопрос «Этично ли это?».
    AGSL NUFR – всё идёт по плану. Словосочетание, полученное из цепочки смен раскладок: FUCK YEAH —> АГСЛ НУФР —> AGSL NUFR.



    Вот что нам удалось вспомнить. Уверены, что у вас тоже есть свои внутренние термины для обозначения всем понятных процессов и состояний. Или, может быть, мы забыли что-то из общеизвестного? Дополним словарь в комментариях!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Xperia Z Ultra — скоро в продаже!

    Грандиозная новость для тех, кто любит все большое и мощное. Мы рады объявить о скором старте официальных продаж топового смартфона Sony Xperia Z Ultra в России! Этот красавец поступит в магазины в самом начале сентября, а рекомендуемая цена составит 29990 рублей.



    Напомним, что Xperia Z Ultra снабжен 6.4-дюймовым экраном TRILUMINOS с фирменной технологией X-Reality и поддержкой рукописного ввода (при помощи помощью стилуса или обычного карандаша), четырехъядерным процессором Qualcomm Snapdragon 800, 8-мегапиксельной камерой с сенсором Exmor RS, а также защищен от воды и пыли в соответствии со стандартом IP58.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Основы Irrlicht Engine для новичков

    Хотелось бы рассказать о такой интересной вещи, как Irrlicht Engine. Для начала определимся что это вообще такое. Irrlicht — это мощный графический 3D движок, написанный на C++. Подходит сие чудо для разработки как простых 2D и 3D приложений, так и для игр. Как и любой другой движок, Irrlicht имеет ряд особенностей, основной из которых является платформенная независимость, то есть программисту, писавшему игру под Windows не нужно переписывать ни строчки кода, чтоб перенести её на устройство под управлением Linux или OSX.

    Установка

    Так как данный урок рассчитан на новичков, мы будем использовать простейший способ установки движка. Для этого нам понадобится code::blocks. Irrlich не очень хорошо дружит с последними версиями блокса, поэтому качаем отсюда и устанавливаем проверенную версию 10.05. Code::blocks уже содержит в своем установщике компилятор, поэтому качать его отдельно не нужно. Далее создаем на жестком диске папку, где будут храниться наши проекты (у меня «D:/IrrlichtDev»). Теперь качаем отсюда последнюю версию Irrlicht'а и разархивируем ее в созданный нами каталог.

    Создание проекта

    Все необходимое у нас есть, настало время для создания проекта. Открываем Code:blocks, далее «File>New>Project», там выбираем «Irrlicht project». Следуя инструкции задаем имя нашему проекту, выбираем тот каталог для хранения, указываем в качестве компилятора «GNU GCC Compiler» и, если просит, говорим где находится движок.

    Все, проект создан, минимальный код сгенерирован автоматически, но если попробовать скомпилировать его, то получим в ответ 2 ошибки. Ничего страшного, просто в 70 строке заменяем
    dimension2d<s32>
    на
    dimension2du
    . Компилируем, запускаем и видим прекрасную, низкополигональную женщину с примитивной анимацией.

    Поздравляю, это ваш первый проект на движке Irrlicht. Давайте сотрем ненужные комментарии (мы же умные, мы и так все поймем) и оставим следующее:

    <code class="cpp">#include <irrlicht.h>
    
    using namespace irr;           //
    using namespace core;          //  Здесь указываем пространства имен движка, для того, чтобы
    using namespace scene;         //     не указывать их каждый раз, когда обращаемся
    using namespace video;         //        к объекту движка.
    using namespace io;            //
    using namespace gui;           //
    
    int main(int argc, char** argv)
    {
    
        IrrlichtDevice *device =                                     // Здесь создаем ссылку на главный объект движка.
            createDevice(EDT_SOFTWARE, dimension2du(640, 480), 16,   // 1-й параметр - это рендер. Сейчас стоит программный 
                false, false, false, 0);                             // рендер,  но можно указать EDT_OPENGL, например.
    
        device->setWindowCaption(L"Hello HABRAHABR");      // Указываем заголовок нашего окошка.
    
        IVideoDriver* driver = device->getVideoDriver();    // Ссылки на видео драйвер и менеджер сцены.
        ISceneManager* smgr = device->getSceneManager();    // Подробнее о них можно почитать в документации.
    
        smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));  // Добавляем в менеджер сцены новую камеру.
    
        while(device->run())          // Это наш основной цикл. Он будет выполняться постоянно, пока работает движок.
        {
            driver->beginScene(true, true, SColor(0,200,200,200));      // Драйвер начинает отрисовку сцены.
    
            smgr->drawAll();                                            // Менеджер сцены рисует свои объекты.
    
            driver->endScene();                                         // Драйвер заканчивает отрисовку сцены.
        }
    
        device->drop();                                                 // Движок перестает работать, можно его удалить.
    
        return 0;
    }
    
    
    </code>

    Сейчас на нашей сцене ничего нет кроме камеры, так что давайте добавим простой кубик. Для этого просто добавим следующую строчку:

    <code class="cpp">IMeshSceneNode * wall = smgr->addCubeSceneNode();
    </code>

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

    <code class="cpp">wall->setMaterialFlag(EMF_LIGHTING,false);
    </code>

    Думаю не нужно объяснять содержание этой строки.
    Чтобы наш рукотворный примитив не был незримо белым, наложим на него текстуру, которую возьмем в стандартном наборе движка. Ниже пишем следующее:

    <code class="cpp">wall->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg")); //Цифра "0" обозначает слой текстуры. 
    </code>

    Запускаем и видим красивый кусок стены.
    Ну что это за кусок стены, если он не вращается? Значит далее пишем:

    <code class="cpp">wall->setRotation(wall->getRotation() + vector3df(0,1,0));
    </code>

    Запускаем, проверяем.

    Раз уж наш куб так истерично вращается, то поддержим психоделическую атмосферу неистово меняющимся цветом фона.
    Создадим некую переменную «i», к которой каждый кадр будет прибавляться единица, а когда она будет достигать значения больше 256, будем сбрасывать её на ноль. Затем эту переменную укажем в качестве значения R, G и B цвета фона при отрисовке сцены. Таким образом, весь наш цикл
    while
    будет выглядеть так:

    <code class="cpp">while(device->run())    {
            int i;
            i++;
            if (i>256) i=0;
            driver->beginScene(true, true, SColor(0,i,i,i));  // Здесь указывается цвет фона.
    
            wall->setRotation(wall->getRotation() + vector3df(0,1,0));
    
            smgr->drawAll();                                            
    
            driver->endScene();                                         
        }
    
    </code>

    Запускаем, наблюдаем.
    Для ленивых вот полный исходный код урока:

    <code class="cpp">#include <irrlicht.h>
    
    using namespace irr;           //
    using namespace core;          //  Здесь указываем пространства имен движка, дл того, чтобы
    using namespace scene;         //     не указывать их каждый раз, когда обращаемся
    using namespace video;         //        к объекту движка.
    using namespace io;            //
    using namespace gui;           //
    
    int main(int argc, char** argv)
    {
    
        IrrlichtDevice *device =                                     // Здесь создаем ссылку на главный объект движка.
            createDevice(EDT_OPENGL, dimension2du(640, 480), 16,   // 1-й параметр - это рендер. Сейчас стоит программный 
                false, false, false, 0);                             //  рендер, но можно указать EDT_OPENGL, например.
    
        device->setWindowCaption(L"Hello HABRAHABR");      // Указываем заголовок нашего окошка.
    
        IVideoDriver* driver = device->getVideoDriver();    //  на  драйвер и менеджер сцены.
        ISceneManager* smgr = device->getSceneManager();    // Подробнее о них можно почитать в документации.
    
        smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));  // Дабавляем в менеджер сцены новую камеру.
    
        IMeshSceneNode * wall = smgr->addCubeSceneNode();
        wall->setMaterialFlag(EMF_LIGHTING,false);
        wall->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
    
        int i = 0;
        while(device->run())          // Это наш основной цикл. Он будет выполняться постоянно, пока работает движок.
        {
          
            i++;
            if (i>256) i=0;
            driver->beginScene(true, true, SColor(0,i,i,i));      // Драйвер начинает отрисовку сцены.
    
            wall->setRotation(wall->getRotation() + vector3df(0,1,0));
    
            smgr->drawAll();                                            // Менеджер сцены рисует свои объекты.
    
            driver->endScene();                                         // Драйвер заканчивает отрисовку сцены.
        }
    
        device->drop();                                                 // Движок перестает работать, можно его удалить.
    
        return 0;
    }
    </code>

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Урок от Yammer: конверсия при регистрации

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

    Пройдите тест

    Хотите проверить ваши навыки продакт-менеджера? Пройдите тест "Сокращаем процесс регистрации" (около 30 минут) перед тем, как читать пост.

    Гипотеза Кристины

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

    Оригинальный процесс регистрации
    Оригинальный процесс регистрации


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

    Вариант 1
    Удалить шаг "Добавьте свое фото" из процесса регистрации и добавить на главную страницу баннер, который просит пользователя добавить фото.

    Добавьте фото
    Запрос на добавление фото на странице продукта

    Вариант 2
    Удалить шаг "Присоединитесь к группам" из процесса регистрации и добавить секцию "Предлагаемые группы" к навигационным ссылкам слева.

    Предлагаемые группы
    Предлагаемые группы в разделе навигационных ссылок

    Вариант 3
    Переместить оба этих шага из процесса регистрации.

    Оригинальный процесс регистрации таков: (1) пользователь заполняет информацию в профиле, (2) пользователь подписывается на коллег или приглашает их, (3) пользователь присоединяется к существующим группам, (4) пользователь загружает фото.

    Результаты теста


    Результаты теста
    Смотри полные результаты здесь

    Все пошло не так, как задумывалось…
    Для новых пользователей в тестовых группах понизилась частота постов и меньше пользователей привлекалось каждый день.

    Что решила Кристина?

    Основываясь на результатах тестирования, Кристина добавила баннер загрузки фото в продукт. Она не добавила модуль "Предлагаемые группы" и не вырезала ни одного шага из процесса регистрации.

    Почему она так поступила?

    Причиной удаления шагов из процесса регистрацией было привлечь больше пользователей в продукт. Несмотря на то, что два варианта достигли этого (удаление присоединения к группам и удаление обоих шагов), Кристина заметила, что новых пользователей стало значительно сложнее удерживать. Немного улучшилось количество привлеченных за неделю пользователей, что, разумеется, очень важно, но это плохо обернулось для активности пользователей — частота постов уменьшилась на 4%, а загрузка фото на 34%.
    Объяснение: После того, как пользователи завершали упрощенный процесс регистрации, тестеры начинали знакомство с продуктом без фото и групп. Они были менее вовлечены в Yammer, чем группа, проходившая оригинальный процесс регистрации, меньше понимали, несет ли Yammer ценность для них, и меньше хотели запостить что-нибудь и пользоваться продуктом дальше

    Но что насчет увеличения в отправке приглашений?

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

    Почему она добавила баннер для фото?

    Количество существовавших пользователей с загруженными фото составило около 9%, что было понятно. Так как они уже прошли процесс регистрации, нам не нужно было волноваться об их удержании, которое усложнялось из-за сокращений. В качестве небольшого бонуса, мы заметили рост количества людей, приглашенных существовавшими пользователями.
    Правда существовала небольшая проблема — количество создаваемых групп уменьшилось на 6%. Кристина приняла это, потому что создание групп было не так важно для сети Yammer, а наша интуиция подсказывала, что фото для профиля важны для удержания пользователя в продукте.
    Объяснение: Баннер добавления фото большой и забирает все внимание со всей левой колонки на себя, так что пользователи не замечают некоторых пунктов меню, например создание группы.

    Вопросы:

    Что насчет метрик/результатов, которые вы не упомянули?
    Мы либо не считали их важными, либо их P-значение был слишком велико, чтобы они были статистически значимыми. Как я упомянул в тесте, мы обычно игнорируем результаты с P-значением большим 0.3, и мы скептически относимся к показателям, P-значение которых больше 0.2. Ученые обычно игнорируют все с P-значением большим 0.05, так что мы еще довольно гуманны.

    Почему Кристина не ввела модуль "Предлагаемые группы"?
    Эта функция выполняла прямо противоположную задачу. Пользователи стали присоединяться к группам на 18.5% реже. Несмотря на это, появилось странное возрастание в количестве постов, но оно было недостаточно велико, чтобы компенсировать это.

    Итоги

    Как удаление шагов из процесса регистрации может быть плохой идеей? Из этого эксперимента, мы поняли, что процесс регистрации — отличное место для того, чтобы вовлечь пользователя в продукт, даже если они еще толком его не видели. Это контринтуитивно, но поведение пользователей часто именно таково.
    Также этот пост показывает, что A/B тестирование не только помогает выбрать из 41 оттенка синего. A/B тестирование может помочь проверить рискованные изменения в продукте.
    Если вам понравился этот пост, прочитайте запись Дрю Диллона о том, почему — не враг, и почему вы не должны ее бояться.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    RailsClub'Moscow 2013 (28 сентября). Новости конференции



    RailsClub’Moscow 2013. Новости конференции.


    Добрый день, друзья
    Хотим поделиться с вами новостями о предстоящем событии RailsClub’Moscow 2013

    Напоминаем, что конференция, посвященная Ruby/Ruby on Rails состоится 28 сентября 2013 в digitaloctober.ru (начало в 10:00). В Москву приедут настоящие ruby звезды, ruby герои, признанные мировым сообществом: Obie Fernandez (США), Linda Liukas (США), Ernie Miller (США), Frederick Cheung (Англия), Eric Hodel (США), Jeremy Evans (США)

    До конференции RailsClub’Moscow 2013 остался один месяц, однако откладывать покупку билетов “на потом” — не советуем. Дешевые билеты уже кончились, поэтому советуем приобрести билет заранее тут.

    Теперь к новостям
    Определились еще два докладчика нашей конференции, ими стали:


    Дмитрий Воротилин из Evrone, с докладом “Зоопарк драйверов для Capybara или как подружиться с Poltergeist”


    Петр Зотов из Evil Martians, с докладом “Foundry: компилируемый диалект Ruby”

    Тезисы докладов и подробности — тут railsclub.ru/schedule

    Кстати, как и в прошлом году, мы планируем взять интервью у каждого докладчика. Начиная с понедельника (2 сентября) мы будем публиковать по несколько интервью в неделю. Да и в целом, планируем рассказать вам все подробности о наших докладчиках и предстоящем событии на протяжении сентября.

    Для нас стало приятной неожиданностью, что нашим спонсором стал Github.com. И они, кстати, очень хотят прислать к нам пару разработчиков github’a, с которыми можно будет пообщаться на конференции (а возможно они и выступят).

    Приглашаем всех на конференцию RailsClub’Moscow 2013. Традиционно, будем вкусно кормить, дарить подарки, проводить конкурсы и лотереи, играть хорошую музыку :) Будет много интересного и познавательного.

    Регистрация и оплата участия в конференции

    Будьте в курсе наших новостей, подписавшись на рассылку на сайте railsclub.ru, и следите за обновлениями:
    railsclub.ru
    http://twitter.com/#!/railsclub_ru
    www.facebook.com/railsclub

    Наши спонсоры
    Генеральный спонсор: undev.ru
    Золотые спонсоры: aviasales.ru, socialquantum.ru
    Серебряные спонсоры: lookatme.ru, github.com

    Организаторы
    evrone.ru и express42.com

    Кстати, мы активно ищем спонсоров. Предложение спонсорам

    Разрабатываете свой проект на Ruby? Ruby приносит вам деньги? Ruby делает вас счастливыми? Внесите и вы свой вклад в развитие Ruby в России! Станьте спонсором самой крупной Российской Ruby on Rails конференции! Помогите нам сделать RailsClub лучше!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Рабовладелец и студент (Success story)

    Добрый день, Хабр!
    После призыва хабраюзера inout делиться своими трудовыми историями, решил написать этот пост не с целью пожаловаться на работодателя или рассказать как мне повезло я умею отстаивать свои права. Моей целью является поднятие боевого духа порядочных и обманутых работников, честно выполняющих своё дело. Рассказ о торжестве сил добра над силами зла будет иметь много букв и длинную предысторию, чтобы читатель проникся ситуацией и ощутил чувство уверенности и победоносного побуждения к действию, так что наберитесь терпения, надеюсь после прочтения у вас будут только положительные эмоции, как и у меня после выхода из этой «грязной» ситуации.

    Империя добра

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

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

    Переход на сторону зла

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

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

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

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

    Что-то пошло не так...

    Но вот однажды произошла череда событий. Мне нужно было уехать на месяц на военные сборы от военной кафедры и я попросил этого сис. админа поработать вместо меня. Когда я приехал, то узнал что парень устал унижаться и увольняется из конторы, а работать я теперь буду с другим человеком. В итоге, контора мне была должна денег уже за два месяца, часть из которых я должен был старому сис. админу, за то что он меня подменял. Работал я 3 недели с другими сис. админами, которые сменялись каждую неделю, потому что не желали работать в таком ужасе. А я в конце концов позвонил бухгалтеру и сказал, что я работать не буду, пока мне не заплатят за три месяца. И тут началось самое интересное!
    Надеюсь вы дочитали до этого...

    Я объявил о выходе из игры заранее и начал ждать пятницы, потому как в пятницу мне, обычно, присылали явки и пароли для подключения к серверу и инструкции, с описанием того что я должен сделать. Но в этот раз я их, как и предполагалось не получил. Прошли выходные и, с понедельника, я начал названивать в бухгалтерию и спрашивать "ну как там с деньгами обстоят вопросы?" © Две недели меня кормили завтраками и обещали вот завтра, вот сегодня вечером, в конце недели, на следующей неделе. И в конце второй недели мне надоело собирать лапшу с ушей и я заявил что если завтра денег не будет, то я «расстроюсь и начну ругаться с вами»(так и сказал). И уж не знаю в чем дело: то ли это звучало убедительно, то ли просто так совпало, но на следующий день меня пригласили приехать за деньгами.

    По приезду в офис меня встретила бухгалтер, отдала пачку пачечку денег, и я, поняв что тут не вся сумма, спросил когда их начинать мучить по поводу остальных денег, на что она сказала, что остальных денег НЕ БУДЕТ, потому что директор сказал, что я недобропорядочный работник и подвел их тем, что не предупредил их за две недели о том, что не буду работать. И тут улыбка сошла с моего лица… я — недобропорядочный… три месяца не платить зарплату… всего три тысячи не хватает… ужасная текучка кадров… и этот человек говорит о моей добропорядочности. Я повернулся, сказал до встречи и с визгом шин уехал от офиса.

    Дело чести

    По дороге на работу я набрал номер моей знакомой и по совместительству юриста и профессионала в трудовом праве и спросил совета, просто совета. Пересказал всю историю, сделал акцент на том, что сумма мизерная и дело не в сумме, а в наглости и отношении к людям. Она, выслушав меня, не стала ничего говорить, а просто спросила телефон бухгалтерии, я даже не знал как зовут этого бухгалтера, как зовут директора, знал только название фирмы и телефон. Я завершил разговор недалеко от своего родного и теплого офиса. Только зайдя в офис, мой телефон зазвонил… звонил тот самый старый-добрый админ, с которым я начинал работать в этой фирме. Первое что я услышал в трубке — дикий смех. Он, ликуя, спрашивал чем я так разозлил «директора» и кому я пожаловался. Я, сначала, не сообразив куда я и кому пожаловался, в ступоре начал спрашивать подробности. Оказалось что звонил ему директор!!!, который раньше брезговал общением с простыми работниками, и наводил на меня справки… кто я такой, что за «студента» такого он привел, что стою, чем опасен и чего мне вообще нужно от честных людей… просил бедного парня, которому, кстати, при увольнении тоже не заплатил ни копейки, повлиять на меня и просить по-хорошему забрать заявление, а то мне будет хуже… Я до конца не поняв про какое заявление идет речь, ловко упускал обсуждение этого вопроса в разговоре, а когда админ услышал что должны мне всего три тысячи рублей, и если мне их отдадут я от них отстану, сказал что перезвонит.

    Бендер, Остап Бендер

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

    Мешочек с золотом

    В общем, пригласили меня забрать мои жалкие деньги в понедельник следующей недели. После выходных, я в приподнятом настроении приехал забирать свои честно заработанные. На пороге офиса меня ждала главный бухгалтер, а рядом с ней стояли мои денежки… да, да, именно стояли… большие такие… в мешке… монетками… Мне заявили что это моя зарплата, а еще на меня будут подавать в суд за клевету. Ну я сказал что с радостью похожу по судам и заглянул в мешок. А бухгалтерша спросила буду ли я пересчитывать. «Обязательно» — сказал я и пнул мешок с деньгами, так что монетки рассыпались по всему холлу, а затем победоносно распинав их по всем дальним уголкам. Это происходило как в самом эпичном моменте фильма: как будто в замедленной съемке и с крутой музыкой. После этого я удалился, подготовил настоящее письмо в ГИТ и прокуратуру и решил забыть об этой истории.

    Послесловие

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

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

    P.S. Все персонажи и ситуации вымышлены и не имеют отношения к реально существующим людям… ага.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru