<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">Post-Engineering</title>
<generator uri="https://github.com/jekyll/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="/feed.xml" />
<link rel="alternate" type="text/html" href="" />
<updated>2015-03-24T18:57:20+00:00</updated>
<id>/</id>
<author>
  <name>Post-Engineering</name>
  <uri>/</uri>
  
</author>


  

<entry>
  <title type="html"><![CDATA[Protobuf не взлетел]]></title>
  <link rel="alternate" type="text/html" href="/blog/no-way-protobuf/" />
  <id>/blog/no-way-protobuf</id>
  <published>2015-03-24T00:00:00+00:00</published>
  <updated>2015-03-24T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Protobuf не взлетел.&lt;br /&gt;
Я воображал, как здорово было бы завести отдельный репозиторий, в котором хранились бы только схемы моделей, собирать их в отдельный артефакт и подключать как зависимость во все взаимодействующие приложения. Серверная часть генерировала бы настоящие — гугловые — протобафные классы, андроидный клиент — свои, на Wire.&lt;br /&gt;
Начав с конца и успев наесться других проблем, я всё-таки дошёл до того момента, когда наивный воображатель обнаруживает отсутствие мавеновских плагинов для протобафа, просто работающих из коробки. И это стало последным фактором против использования protobuf.&lt;br /&gt;
Дальше — JAXB.  &lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/no-way-protobuf/&quot;&gt;Protobuf не взлетел&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 24, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Android AsyncTasks]]></title>
  <link rel="alternate" type="text/html" href="/blog/android-asynctask/" />
  <id>/blog/android-asynctask</id>
  <published>2015-03-22T00:00:00+00:00</published>
  <updated>2015-03-22T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Использовать AsyncTask’и для выполнения HTTP-запросов — это просто космос!&lt;br /&gt;
Затрудняюсь даже подобрать подходящую аналогию подобному неуместному использованию технологий. Добавьте сюда (странные?) ограничения, например, что создавать таски можно только из UI-потока, и только из него же нужно вызывать &lt;code&gt;execute(Params…)&lt;/code&gt;, и что получится? Ах да, ведь начиная с 3.0 версии андроида AsyncTask’и по умолчанию выполняются в одном background-потоке, так что об одновременном запросе сразу нескольких ресурсов можно забыть.&lt;br /&gt;
Я не говорю, что AsyncTask’и плохие, я хочу сказать, что по умолчанию выбирать для работы с IO именно их — странная рекомендация.   &lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/android-asynctask/&quot;&gt;Android AsyncTasks&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 22, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Android Injector]]></title>
  <link rel="alternate" type="text/html" href="/blog/android-injector/" />
  <id>/blog/android-injector</id>
  <published>2015-03-19T00:00:00+00:00</published>
  <updated>2015-03-19T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Возможно потому, что под Андроид нужно писать на джавке, так хочется притащить в андроидное приложение некоторые ставшие привычными вещи. Например, хочется иметь возможность попросить заинжектить все зависимости компонента. Нет, конечно, хочется, чтобы этого даже просить не нужно было, но в андроидной инфраструктуре это будто бы невозможно.  &lt;/p&gt;

&lt;p&gt;Единственный [полиморфный] контекст до которого в Андроиде могут дотянуться все компоненты, участвующие в обычном жизненном цикле, — это &lt;code&gt;Application&lt;/code&gt;. С другой стороны, завязывать все-все-все компоненты на какой-то конкретный апп (и пораждать циклические зависимости) нет никакого желания, и на свет просится интерфейс &lt;code&gt;Injector&lt;/code&gt; с единственным методом &lt;code&gt;void inject(Object o)&lt;/code&gt;. Более того, этот тощий интерфейс даже заселяется в отдельный, специально для него созданный, модуль, за что на работе меня некоторые мои коллеги бы прокляли.&lt;br /&gt;
Сам же Application использует Dagger от Square, подробнее о котором можно &lt;a href=&quot;http://square.github.io/dagger/&quot;&gt;тут&lt;/a&gt; почитать.  &lt;/p&gt;

&lt;p&gt;Даггер непривычен тем, что в нём при описании модулей нужно перечислять все классы, которым будут предоставляться зависимости. Каждый раз, создав новый фрагмент и попробовав вызвать &lt;code&gt;.inject(this)&lt;/code&gt; из метода &lt;code&gt;onCreate&lt;/code&gt;, прийдётся встречаться с сообщением об ошибке (времени исполнения, конечно же), добавлять фрагмент в список &lt;code&gt;injects&lt;/code&gt; одного из модулей даггера и пересобирать приложение.  &lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/android-injector/&quot;&gt;Android Injector&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 19, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Клиент-серверное взаимодействие в Android-приложении]]></title>
  <link rel="alternate" type="text/html" href="/blog/client-server-interaction/" />
  <id>/blog/client-server-interaction</id>
  <published>2015-03-18T00:00:00+00:00</published>
  <updated>2015-03-18T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Пришло время заняться серверной частью и клиент-серверным взаимодействием.&lt;br /&gt;
На бэкэнде всё почти обычно: Java-приложение, Spring Boot, Jackson, в ближайшем будущем добавится Hibernate.&lt;br /&gt;
Довольно странным получился Maven-layout приложения. Предполагается, что новые функциональные возможности (features) будут проходить сквозь все слои приложения (по сути являясь под-приложениями), все они будут наследоваться от абстрактного Maven-проекта Feature, и подключаться к основному приложению будут как &lt;code&gt;runtime&lt;/code&gt;-зависимости.  &lt;/p&gt;

&lt;p&gt;Андроидная часть реализована отвратительно. Сейчас получилось, что я рассчитываю, что во время обработки ответа фрагмент для аутентификации всё ещё отображается, что активити для этого фрагмента всё ещё существует. Это повод для будущих улучшений; когда таких фрагментов наберется 3-4, станет возможным выделить их общие проблемы и предложить какой-то паттерн для их решения (а может быть кто-нибудь подскажет что-нибудь умное к тому моменту). Нагромождение вырожденных &lt;code&gt;AsyncTask&lt;/code&gt;ов усилилось, добавился &lt;code&gt;ValidateTokenTask&lt;/code&gt;. Общение с игровым сервером реализовано хардкорно — через &lt;code&gt;HttpURLConnection&lt;/code&gt;. Классы, описывающие ответы сервера, дублируются (и могут привести к сложно выявляемым ошибкам, если забыть скопировать изменения между проектами).&lt;br /&gt;
Изначально я думал, что можно было бы попробовать вообще не описывать игровые сущности как Java-классы самому, а генерировать их по какой-нибудь схеме (и делать это как при сборке сервера, так и для клиента); Hibernate тоже можно было бы подключить через XML-конфигурацию. Но всё-таки между тем, с чем удобно работать на сервисном уровне, и объектами, пригодными для клиент-серверного общения, нередко целая пропасть.  &lt;/p&gt;

&lt;p&gt;Серверная проверка корректности гугл-токена и получение информации о пользователе тоже сделаны хардкорно, тоже через &lt;code&gt;HttpURLConnection&lt;/code&gt;. Возможно, если когда-нибудь на бэкэнде появится необходимость более тесной интеграции с сервисами Гугла, то и получение информации о пользователе можно будет заменить на библиотечный.&lt;br /&gt;
Сложным оказался вопрос о том, что возвращать клиенту в случае успешной аутентификации. Поэтому пока что возвращается только результат: &lt;code&gt;success&lt;/code&gt;/&lt;code&gt;fail&lt;/code&gt;/&lt;code&gt;error&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Удостоверившись, что весь цикл аутентификации работает, я отправил изменения в соответствующие ветки и решил немного заняться инфраструктурными вещами в андроидной части игры.  &lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/client-server-interaction/&quot;&gt;Клиент-серверное взаимодействие в Android-приложении&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 18, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Google-аутентификация в андроид-приложении]]></title>
  <link rel="alternate" type="text/html" href="/blog/Google-login/" />
  <id>/blog/Google-login</id>
  <published>2015-03-12T00:00:00+00:00</published>
  <updated>2015-03-12T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Как проще всего сделать аутентификацию в приложении под Андроид? Использовать Google аккаунт!&lt;br /&gt;
На самом деле нет.&lt;br /&gt;
Если вы знаете что делать, то простая форма с логином и паролем обойдется меньшей кровью.&lt;br /&gt;
В Android Studio есть опция создания activity для аутентификации через Google+, но генерируется настолько устаревшая форма для логина, что результат даже отказывается компилироваться.  &lt;/p&gt;

&lt;p&gt;В первую очередь, ещё до того как приступить к написанию кодулек, нам понадобится зарегистрировать наше приложение в &lt;a href=&quot;https://code.google.com/apis/console/&quot;&gt;Google APIs Console&lt;/a&gt;, а для этого нужен SHA ключа, которым подписано приложение. Для debug keystore можно выполнить команду
&lt;code&gt;keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v&lt;/code&gt; (пароль android).&lt;br /&gt;
Также &lt;strong&gt;обязательно&lt;/strong&gt; нужно во вкладке Consent screen выбрать Email address (на обнаружение этой ошибки ушло 20 минут моих нервов).&lt;br /&gt;
Если приложение не зарегистрировать, &lt;code&gt;GoogleAuthUtil.getToken&lt;/code&gt; будет возвращать &lt;code&gt;null&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Код получения токена я практически полностью скопировал из примера, однако оставлять его в таком состоянии посчитал невозможным. Statefull логику хорошо бы сразу перенести во фрагмент, переживающий пересоздание активити (например, при повороте телефона).&lt;br /&gt;
Сигнатура &lt;code&gt;AsyncTask&amp;lt;Void, Void, Void&amp;gt;&lt;/code&gt; явно намекает на то, что &lt;code&gt;AsyncTask&lt;/code&gt; здесь использован не по назначению, но это повод для будущих изменений.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/Google-login/&quot;&gt;Google-аутентификация в андроид-приложении&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 12, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Версия Android и сборка Gradle]]></title>
  <link rel="alternate" type="text/html" href="/blog/graddle/" />
  <id>/blog/graddle</id>
  <published>2015-03-10T00:00:00+00:00</published>
  <updated>2015-03-10T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Идея ориентироваться только на пятый Андроид на фоне статистики использования выглядит не очень радужной: сейчас устройств с Андроидом пятой версии меньше процента.&lt;br /&gt;
Jelly Bean (4.1) с его 82% смотрится гораздо лучше.&lt;/p&gt;

&lt;p&gt;В качестве lifecycle management инструмента я решил впервые попробовать Gradle вместо привычного Maven. Наверное, если в разработке проекта делается упор на скорость выхода в маркет, этого делать и не стоило.&lt;br /&gt;
За более компактный синтаксис приходится платить. Например, в строке с указанием зависимости Android Studio не подскажет вам доступные версии артефакта. В репозитории с проектом появляется мусор, необходимый Gradle для работы, включая .jar-файл.&lt;br /&gt;
Но все неудобства и непривычности должны в будущем компенсироваться, если верить &lt;a href=&quot;http://tools.android.com/tech-docs/new-build-system/user-guide&quot;&gt;Gradle Plugin User Guide&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/graddle/&quot;&gt;Версия Android и сборка Gradle&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 10, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Кулонные бои под Андроид]]></title>
  <link rel="alternate" type="text/html" href="/blog/starting-android-game/" />
  <id>/blog/starting-android-game</id>
  <published>2015-03-09T00:00:00+00:00</published>
  <updated>2015-03-09T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;Хочется сделать что-то похожее на форматные (кулонные) бои в Бойцовском Клубе.&lt;br /&gt;
Приложение для Андроида с минимально возможной игровой инфраструктурой: нет магазинов, нет городов, нет чата, вообще ничего нет. В первой версии нельзя будет даже выбрать архетип персонажа (уворот/крит). Нет заявок на бои: в первой версии все бои проходят в формате 2 vs 2, команды формируются автоматически.&lt;br /&gt;
Опять же в целях упрощения, приложение под последний Андроид, никакого pixel-perfect. С любовью к библиотекам от Square.&lt;br /&gt;
На бэкэнде Спринг, вероятнее всего Спринг Бут. Для клиент-серверного взаимодействия в первую очередь попробую Atmosphere. Интеграция через STOMP over WebSocket в данном случае выглядит слишком сложной; клиент подписывается сразу на все события для своего персонажа и смысла в нескольких эндпоинтах нет.&lt;br /&gt;
Следить за развитием событий можно по тегу androgame.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/starting-android-game/&quot;&gt;Кулонные бои под Андроид&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on March 09, 2015.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[DNS внутри контейнера]]></title>
  <link rel="alternate" type="text/html" href="/blog/docker-dns/" />
  <id>/blog/docker-dns</id>
  <published>2014-10-01T00:00:00+00:00</published>
  <updated>2014-10-01T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Сегодня расскажу как поднять свой DNS сервер в Docker контейнере.&lt;br /&gt;
Уже почти год как сам пользуюсь таким в &lt;a href=&quot;https://www.digitalocean.com/?refcode=06c4ef09e5cc&quot;&gt;Digital Ocean&lt;/a&gt;. Приватной сети у данного провайдера все еще нет. Поэтому все мои машинки соединены через OpenVPN и в этот же VPN прокинут DNS сервер, через который осуществляется service location. О такой конфигурации и пойдет речь.&lt;/p&gt;

&lt;h2 id=&quot;section&quot;&gt;Собираем образ&lt;/h2&gt;
&lt;p&gt;Cоберем образ сервера с помощью Docker.   &lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;## Dockerfile
FROM ubuntu
MAINTAINER Denis Golovachev

RUN apt-get update
RUN apt-get install -y bind9 

CMD usr/sbin/named -c /etc/bind/named.conf -f
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker build -t server/bind .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И заберем из контейнера папку с конфигурацией DNS сервера.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bindId=$(docker run -d serer/bind)
docker cp $bindID:/etc/bind ./bind
docker stop $bindID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Теперь мы можем отредактировать конфигурацию DNS сервера&lt;/p&gt;

&lt;h2 id=&quot;dns-server&quot;&gt;DNS Server&lt;/h2&gt;
&lt;p&gt;Добавим своих DNS записей. Для этого создадим свою доменную зону &lt;code&gt;.tapcat&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# bind/named.conf.local - Добавим запись вида
include &quot;/etc/bind/named.conf.tapcat&quot;;
# bind/named.conf.tapcat - Создадим файл
zone &quot;tapcat&quot; {
        type master;
        file &quot;/etc/bind/db.tapcat&quot;;
};
# bind/db.tapcat - Создадим файл. За доп опциями можно обратиться в man bind
$TTL 10
$ORIGIN tapcat.

@ IN SOA        ns1.tapcat hostmaster.tapcat. (
                    2014040901 ; Serial
                    2h ; Refresh
                    1h ; Retry
                    1w ; Expire
                    2h ; Negative Cache TTL
)

@               IN      NS      ns1.    ; Master

ns1.tapcat.         IN       A       10.8.0.19
master.tapcat.      IN       A       10.8.0.19

cname.tapcat.       IN      CNAME   master.tapcat.
cname2.tapcat.      IN      CNAME   master.tapcat.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Запускаем с нашей конфигурацией&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -d -p 53:53/udp -v /home/postengineering/bind9/conf:/etc/bind -c 25 -m 30m server/bind
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Готово. У нас теперь свой ДНС сервер.  Давайте прокинем его в OpenVPN. &lt;/p&gt;

&lt;h2 id=&quot;openvpn&quot;&gt;OpenVPN&lt;/h2&gt;
&lt;p&gt;Машина, на которой установлен bind должна находиться в VPN сети. После этого мы редактируем конфиг VPN сервера&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# /etc/openvpn/server.conf - добавим строчку
push &quot;dhcp-option DNS 10.8.0.3&quot;
# где 10.8.0.3 - адрес машины с VPN сервером
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Изменяем конфигурацию наших VPN клиентов&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# etc/openvpn/client.conf - добавляем
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И кладем данный update-resolv-conf рядышком. Сам скрипт лежит у вас в репозитории пакетов или гуглится.&lt;br /&gt;
Перезапускаем bind:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -d -p $VPN_IP:53:53/udp -v /home/postengineering/bind9/conf:/etc/bind -c 25 -m 30m server/bind
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Готово. Теперь в нашей внутренней сети есть свой маленький DNS сервер.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;/blog/docker-dns/&quot;&gt;DNS внутри контейнера&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 01, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Месяц с Хаскелем]]></title>
  <link rel="alternate" type="text/html" href="/blog/month-with-haskell/" />
  <id>/blog/month-with-haskell</id>
  <published>2014-09-28T00:00:00+00:00</published>
  <updated>2014-09-28T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Вот и заканчивается месяц Хаскеля.&lt;br /&gt;
Бинарники, библиотеки, линковка.
Писали на Хаскеле веб. Сейчас же на всем пишут веб! Удалось познакомиться с двумя веб фреймворками: Yesod и Snap Framework.&lt;/p&gt;

&lt;h2 id=&quot;snap-framework&quot;&gt;Snap Framework&lt;/h2&gt;
&lt;p&gt;Такой, аля Sinatra для Хаскеля. Простенький, приятный. Однако, чтобы написать что-нибудь сложнее чем hello-world - потребует от вас написать пару плагинов. Готовых компонентов мало. Молодой фреймворк.&lt;/p&gt;

&lt;h2 id=&quot;yesod&quot;&gt;Yesod&lt;/h2&gt;
&lt;p class=&quot;pull-right&quot;&gt;&lt;img src=&quot;/images/yesod.png&quot; alt=&quot;Yesod logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Похож на Django. Очень много кодогенерации. ORM, JS, CSS, HTML, JSON Types - все это генерится. Изменил шаблон главной страницы - попал на перекомпиляцию. Очень грустно писать JS/CSS.&lt;br /&gt;
А в остальном - ВЕЩЬ. Все, что хочешь: авторизации, шаблоны, маппинг параметров, typesafe url, тесты. Кстати, о тестах. &lt;/p&gt;

&lt;h2 id=&quot;tests&quot;&gt;Tests&lt;/h2&gt;
&lt;p&gt;Что-то не очень в Хаскель сообществе принято тесты писать. А я люблю тесты. С Yesod ситуация  приемлимая. Можно написать тесты для JSON Rest. Присутствуют селекторы для построения HTML ассертов. Напрягает вывод при падении теста. Ну не пишет Yesod что сломалось. Пишет, что завалился. А разобраться почему - отдельный квест. 
К тестам обязательно нужен continuous integration. Тут засада. Дня 2 разбирался. Во первых - Yesod собирается минут 40 у меня локально на CoreI5. На тревисе это время можно легко умножить на 2. Да еще и билд тревиса постоянно норовит упасть со странными ошибками.&lt;br /&gt;
В итоге собирали на тревисе Docker образ из предзаготовленного, с установленным Yesod. Кстати, образ доступен на Docker Hub &lt;a href=&quot;https://registry.hub.docker.com/u/wonderbeat/yesod/&quot;&gt;тыц&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;deploy&quot;&gt;Deploy&lt;/h2&gt;
&lt;p&gt;Опять же, не JVM. Бинарник собирается под платформу. Кросскомпиляцию делать лень. С тревиса забирать - странная затея. Опять помог Docker с предзаготовленным Yesod.&lt;br /&gt;
Памяти жрет много. Сравнимо с JVM. Даже, иногда больше. Но это уже проблема кривых рук. Ведь в Хаскеле, по умолчанию, используется lazy-evaluation. Написал красивую рекурсивную функцию, а по памяти просел мегабайт на 10. Следить надо. А следить - сложно.&lt;/p&gt;

&lt;h2 id=&quot;development&quot;&gt;Development&lt;/h2&gt;
&lt;p&gt;Разработка на Хаскеле легко может напугать ребят из мира Java/C#. Тут все очень похоже на С++. Компилятор чего-то постоянно собирает. Странные, ничего не говорящие ошибки. Циклические импорты. Линковка.&lt;br /&gt;
Все плохо с IDE. Почитав интернеты, я остановился на SublimeHaskell. Автокомплит. Тесты запускаются автоматически. Но, автокомплит глупый-глупый. Можно узнать тип используемой функции. Опять же - не всегда.&lt;/p&gt;

&lt;p&gt;Хаскель - вещь классная. Огорчает инфраструктура. Очень похоже на ситуацию с NPM. Полно пакетов. Документации ноль. Как настраивать - не понятно. Сырые инструменты, велосипеды.&lt;br /&gt;
Надо попробовать написать что-нибудь без веба. Пойдемте на хакатон?&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;/blog/month-with-haskell/&quot;&gt;Месяц с Хаскелем&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on September 28, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Haskell hackathon]]></title>
  <link rel="alternate" type="text/html" href="/blog/haskell-hackathon/" />
  <id>/blog/haskell-hackathon</id>
  <published>2014-09-01T00:00:00+00:00</published>
  <updated>2014-09-01T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Астрологи объявили месяц изучения Хаскеля!
Запускаем хакатон.
Таймслот - месяц.
Задача - выпустить приложение под Иос/Андроид с веб сервером.
Код тут - &lt;a href=&quot;https://github.com/TimeAttack&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
Полетели!&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;/blog/haskell-hackathon/&quot;&gt;Haskell hackathon&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on September 01, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Machine-learning bot]]></title>
  <link rel="alternate" type="text/html" href="/blog/space-marines/" />
  <id>/blog/space-marines</id>
  <published>2014-08-25T00:00:00+00:00</published>
  <updated>2014-08-25T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;У нас в компании прошел турнир по вот такой пошаговой игре, где программисты должны написать
алгоритм для захвата галлактики дронами.
Таких игр довольно много, ага. Однако, прямо во время анонса турнира, в Лас-Вегасе проходил DEFCON 22, где я засек очень интересный доклад &lt;a href=&quot;https://www.defcon.org/html/defcon-22/dc-22-speakers.html&quot;&gt;I am a legend: Hacking Hearthstone with machine learning&lt;/a&gt;
В голове зародилась идея. А вдруг можно написать бота для этой игры с использованием machine learning и без опыта его использования.&lt;/p&gt;

&lt;h1 id=&quot;section&quot;&gt;Прототип&lt;/h1&gt;
&lt;p&gt;Прототип собрали за 4 дня. Писали на Kotlin с использованием библиотеки &lt;a href=&quot;https://mahout.apache.org/&quot;&gt;Mahout&lt;/a&gt;.
Жаль что библиотека скудна на примеры и приходилось очень много вычитывать в мейл-переписках коммьюнити.
После того, как собрали базу в 20 мб игр, оказалось что бот чему-то научился. Он захватывал соседнюю планету (выход в галлактику). Загружал ее дронами “выше крыши” и отсижывался. Такая тактика позволяла ему занимать не ниже второго места в тренировках.
Но, времени уже не было и с этим крысоботом мы пошли на полуфинальные игры&lt;/p&gt;

&lt;h1 id=&quot;section-1&quot;&gt;Полуфинал&lt;/h1&gt;
&lt;p&gt;И прошли. Очень глупо, но прошли. Во время трансляции нашей игры коментаторы постоянно думали, что наш бот отвалился и не играет. А это была его тактика ;).
Бота решили подтюнить.&lt;/p&gt;

&lt;h1 id=&quot;section-2&quot;&gt;Финал&lt;/h1&gt;
&lt;p&gt;На финал мы решили схитрить. Первые ходы в каждой игре делал алгоритм коллеги, который не прошел в финал. После этого машин лернинг брал управление на себя. Посмотрев, как дело обстоит на тренировке, мы увидели, что машина начинает нападать при такой завязке. И выигрывает. Все тренировочные бои такая машина выиграла.
Но, проиграла турнир. Играла не очень. И тут не понятно почему. Толи ошибка у нас в программе, толи базу собрали маленькую, толи алгоритмы соседских врагов были направлены на ближайшего соседа - нашего бота.
Но, это не важно. У нас получился очень интересный бот. Бот, следующий ход которого не могут предсказать даже разработчики. И это здорово!&lt;/p&gt;

&lt;p&gt;Код нашего бота лежит на гитхабе - &lt;a href=&quot;https://github.com/WonderBeat/suchmarines&quot;&gt;вот тут&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/space-marines/&quot;&gt;Machine-learning bot&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on August 25, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[4 Digit Pins collection]]></title>
  <link rel="alternate" type="text/html" href="/blog/4-digit-pins/" />
  <id>/blog/4-digit-pins</id>
  <published>2014-04-18T00:00:00+00:00</published>
  <updated>2014-04-18T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Завалялась у меня коллекция четырехзначных пинов платежных операций. Делюсью
Коллекция содержит уникальные пользовательские пины отсортированные по популярности.
Статистика собрана на основе дампа десяти тысяч пинов.
Может кому и пригодится.
Откуда - секрет ;)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/WonderBeat/11028348&quot;&gt;4 digit PINS&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/4-digit-pins/&quot;&gt;4 Digit Pins collection&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on April 18, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Большая красная кнопка]]></title>
  <link rel="alternate" type="text/html" href="/blog/big-red-button/" />
  <id>/blog/big-red-button</id>
  <published>2014-02-10T00:00:00+00:00</published>
  <updated>2014-02-10T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Раньше я только подозревал, но сейчас уже полностью уверен, что аутсорс - унылое говно. А помогла мне вот такая история.&lt;/p&gt;

&lt;p&gt;Месяц назад нашей команде прилетела задача. Баг. На мобильном приложении не отображается кнопка. Кнопка красная. Важная. С ее помощью можно было посмотреть различные конфигурации товара. Например, комплектации выбранного вами ноутбука.&lt;/p&gt;

&lt;p&gt;Фигня делов, сказал девелопер и взялся за работу. Сравнив XML дамп старого и нового бекенда, а задача у нас именно поддержать мобильное приложение при переезде на новый бекенд, выяснили, что не приходит два дополнительных поля. Добавили за несколько дней (аутсорс ведь ;) ).&lt;/p&gt;

&lt;p&gt;Следующий шаг задачи - тестирование. “Где можно увидеть эту кнопку?” - спросил тестировщик. “Ой, не знаю где у вас на тестовом окружении она может появиться.” - был ответ. Ну да ладно. Через 2 дня задача закрылась.&lt;/p&gt;

&lt;p&gt;Но, самое интересное произошло на демо. Демонстрация задачи заказчику провалилась. Заказчик решил нажать на кнопку! И приложение закрылось. Раз… и закрылось. “Ой” - сказал девелопер. “Ой” - сказал тестировщик. Никто не нажал на красную кнопку до демо.&lt;/p&gt;

&lt;p&gt;И это тут везде. Стремление к тому, чтобы закрыть задачу вытеснело здравый смысл. Никто даже не задумывается. Закрывай таски - получай деньги.&lt;/p&gt;

&lt;p&gt;Но, я все еще хочу это исправить.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/big-red-button/&quot;&gt;Большая красная кнопка&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on February 10, 2014.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Меньше кнопок]]></title>
  <link rel="alternate" type="text/html" href="/blog/fewer-buttons/" />
  <id>/blog/fewer-buttons</id>
  <published>2013-11-14T00:00:00+00:00</published>
  <updated>2013-11-14T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;p&gt;В детстве у меня была Sega, а у моего товарища был самый настоящий компьютер. Я был маленький и завидовал, что у него большая клавиатура, на которой так много кнопок.
Потом мы как-то раз попробовали у него дома поиграть в Mortal Combat. Вдвоем на этой прекрасной клавиатуре попасть в нужные кнопки оказалось довольно непростым занятием, да ещё под неестественным углом запястья выворачивать приходилось.
Делайте меньше кнопок, пожалуйста.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/fewer-buttons/&quot;&gt;Меньше кнопок&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on November 14, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Домен]]></title>
  <link rel="alternate" type="text/html" href="/blog/domain/" />
  <id>/blog/domain</id>
  <published>2013-11-01T00:00:00+00:00</published>
  <updated>2013-11-01T00:00:00+00:00</updated>
  <author>
    <name>Maksim</name>
    <uri></uri>
    <email>cornelius@thewhip.com</email>
  </author>
  <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Уровень предметной области (Domain Layer) или Уровень модели (Model Layer).
Отвечает за представление понятий прикладной предметной области, рабочие состояния, деловые регламенты.
Именно здесь контролируется и используется текущее состояние прикладной модели, пусть даже технические подробности манипуляции данными делегируются инфраструктуре.
&lt;em&gt;Этот уровень является главной, алгоритмической частью программы.&lt;/em&gt;
Domain-Driven Design&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Почему же я всё чаще вижу как создаются приложения, где есть только “entity” и “dto”?
В какой момент на вопрос о том, зачем нужен какой-то класс-сервис, стало нормой отвечать, что он нужен “для работы с энтити”?
Вопросы риторические.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/domain/&quot;&gt;Домен&lt;/a&gt; was originally published by Maksim at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on November 01, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Webhook handler with netcat]]></title>
  <link rel="alternate" type="text/html" href="/blog/simple-webhook-handler/" />
  <id>/blog/simple-webhook-handler</id>
  <published>2013-10-23T00:00:00+00:00</published>
  <updated>2013-10-23T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Решил попробовать запустить деплой по нотификации от CI. Travis умеет дергать урлы при удачном билде. Осталось только среагировать на это.&lt;/p&gt;

&lt;p&gt;Для реагирования нужна програмка. Програмка простая. Висит, слушает порт, а по сигналу запускает скрипт.
Пошарив на гитхабе Я обнаружил маленькую тележку таких програм. Но, чаще всего они были заточены на определенные сервисы (Travis, Github), и для их запуска
было необходимо снабдить машину Python-ом или NodJS-ом.
Ставить NodeJS ради WebHook хендлера, запускающего скрипт!? Не, не мой вариант. Точно. Мы сделаем это “Linux Way”&lt;/p&gt;

&lt;p&gt;Итак.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Задача: запустить скрипт после того, как нам придет event от CI [HTTP GET]&lt;/li&gt;
  &lt;li&gt;K.I.S.S.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Нам нужен сервер? Возьмем могучий netcat! В большинстве дистрибутивов он идет в комплекте.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
while true; do
  echo &quot;Deploy starts NOW!&quot; | nc -l -p 1500 -q 0;
  ./deploy.sh
  sleep 1m;
done
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Вот так. В несколько строчек.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/simple-webhook-handler/&quot;&gt;Webhook handler with netcat&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 23, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[CORS and Third-Party Cookies]]></title>
  <link rel="alternate" type="text/html" href="/blog/cors-and-thirdparty-cookies/" />
  <id>/blog/cors-and-thirdparty-cookies</id>
  <published>2013-10-17T00:00:00+00:00</published>
  <updated>2013-10-17T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Всегда хотел написать веб приложение в котором клиент полностью отделен от сервера, находится на другом домене и с сервером только по REST общается. Встрял на одной проблеме. Довольно интересной.&lt;/p&gt;

&lt;p&gt;Решил Я попробовать сделать следущую архитектуру. Веб приложение находится на основном домене, а сервер с логикой располагается на другом.
Технологии позволяют: &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing&quot;&gt;Cross-Origin-Resource-Sharing&lt;/a&gt; уже в браузерах.
Механизм такой: приложение запрашивает сервер на другом домене, а он отвечает с заголовками&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
Access-Control-Allow-Origin: http://your-webapp.com
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Браузер не ругается. Полет нормальный.&lt;/p&gt;

&lt;p&gt;Следующий этап приложения - это авторизация. Как мы знаем, в качестве идентификатора пользователся в вебе используются Cookies. И, вроде они нам подходят.
Согласно спецификации (&lt;a href=&quot;http://www.w3.org/TR/cors/&quot;&gt;link&lt;/a&gt;), для использования идентификаторов (credentials) при работе с CORS, нам нужно сделать&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;invocation.open(&#39;GET&#39;, url, true);
    invocation.withCredentials = true; # выставить флаг на клиенте
    invocation.onreadystatechange = handler;
    invocation.send();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;
Access-Control-Allow-Credentials: true # добавить заголовок в ответ на сервере
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;С этого момента становится возможным передача Cookie / Set-Cookie заголовков. В ином случае их отрежет браузер.
Теперь должно работать. И, даже работает. Но не везде. Далеко не везде.&lt;/p&gt;

&lt;h2 id=&quot;third-party-cookies&quot;&gt;Third-Party Cookies&lt;/h2&gt;
&lt;p&gt;Куки третьей стороны ;) &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_cookie&quot;&gt;link&lt;/a&gt;.
В двух словах: браузер позволяет установить куки для домена, отличного от домена в адресной строке. Это может быть сделано, в результате запроса картинки/скрипта.
TP Cookies используются компаниями, которые хотят следить за пользователями в интернетах.
И да-да. Кнопка “+1” и “like” тоже следит за нами. Именно с помощью third-party-cookies. А потом удивляешься, почему после того, как ты посмотрел сайт про ремонт, facebook начал тебя объявлениями тематическими заваливать.&lt;/p&gt;

&lt;h2 id=&quot;intersection&quot;&gt;Intersection&lt;/h2&gt;
&lt;p&gt;Так что же произойдет, если мы будем использовать CORS при включенной блокировке Third-Party Cookies?
Я попробовал. И браузер отказался принимать Cookies. Вот она - проблема!&lt;/p&gt;

&lt;h2 id=&quot;firefox--safary&quot;&gt;Firefox &amp;amp;&amp;amp; Safary&lt;/h2&gt;
&lt;p&gt;По умолчанию, Third-Party-Cookies запрещены в Firefox &amp;amp; Safary.
Как же без этого работают встраиваемые виджеты!? Например, виджет Disqus, который можно наблюдать под статьей.
Ха-ха. А ведь он не работает. Точнее, работает, но не полностью. Не работает OAuth авторизация. Похоже, Disqus об этом знает (&lt;a href=&quot;http://help.disqus.com/customer/portal/articles/466235-enabling-cookies&quot;&gt;link&lt;/a&gt;), но ничего сделать не может.&lt;/p&gt;

&lt;h2 id=&quot;section&quot;&gt;Пичаль&lt;/h2&gt;
&lt;p&gt;Удостоверившись в данном поведении Я расстроился и написал статью до текущего параграфа. Но, желание отделить клиент и сервер не уменьшилось. И Я решил поискать архитектурные решения среди современных веб сервисов.&lt;/p&gt;

&lt;p&gt;Зашел в linkedIn - ужаснулся какая кака в коде. Решения не нашел.
Зашел в Yammer. И нашел! Оказалось, что Яммер использует cometd based сервис, который находится на домене rt-123.rt.yammer.com. И использует CORS и Cookie. И… невероятно… такая связка работает в браузере с включенной блокировкой third-party-cookies.&lt;/p&gt;

&lt;h2 id=&quot;section-1&quot;&gt;Эксперимент&lt;/h2&gt;
&lt;p&gt;Я не понял, почему работает у них, а у меня нет. Но, Я был намерен это узнать =)
Догадки, которые были на тот момент:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;SSL - Возможно, хитрые браузеры не считают за third-party домены с идентичным wildcart SSL сертификатом?&lt;/li&gt;
  &lt;li&gt;Я опять продолбал важный параграф в спецификации CORS&lt;/li&gt;
  &lt;li&gt;Хаки со стороны Yammer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Больше всего надежды было на SSL. А зря. Как оказалось, wildcard сертификаты распространяются только на поддомены первого уровня. А тут rt-123.rt.yammer.ru - второго. Не работает. И правда, проверив сертификат rt домена, Я обнаружил, что он другой.&lt;/p&gt;

&lt;p&gt;Хаков со стороны Yammer-a обнаружено не было. Спецификацию Я перечитал.
И всеже оно заработало.&lt;/p&gt;

&lt;h2 id=&quot;third-party&quot;&gt;Не third-party&lt;/h2&gt;
&lt;p&gt;Оказалось, что браузер блокирует запросы к поддоменам по причине cross-origin, однако не считает их third-party. Ох, сложно. Сейчас объясню.&lt;/p&gt;

&lt;p&gt;Возьмем два домена&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
yourdomain.com
api.tapcat.net
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;и &lt;code&gt;tapcat.net&lt;/code&gt; - основной домен, с которого будем делать запросы.
При использовании CORS мы явно можем разрешить доступ к выбранным доменам. При разрешенных third-party cookies работа и с одним и с другим доменом не доставит хлопот.
А вот, если TPC заблокированы….
В этом случае, оказалось, что браузер срежет куки для домена &lt;code&gt;yourdomain.com&lt;/code&gt;, но позволит проставить cookie для домена &lt;code&gt;api.tapcat.net&lt;/code&gt;.
Глубина поддоменов не учитывается и все работает даже для: &lt;code&gt;dev.api.tapcat.net; a.b.c.d.tapcat.net&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cors-cookie-chrome.png&quot; alt=&quot;cors-third-party-chrome&quot; /&gt;
&lt;img src=&quot;/images/cors-cookie-firefox.png&quot; alt=&quot;cors-third-party-firefox&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Получается, оно работает потому что текущий Origin содержится в данном домене!?&lt;/p&gt;

&lt;h1 id=&quot;i-need-proof&quot;&gt;I need proof&lt;/h1&gt;
&lt;p&gt;Решение работает в современных браузерах. Данное поведение должно быть стандартизировано!
Ищем стандарт!
Нам подходят документы:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6265.txt&quot;&gt;HTTP State Management Mechanism&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.w3.org/TR/cors/&quot;&gt;W3C CORS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Первый говорит, что есть такие third-party cookies, которые user agent может блокировать. А как отличить одни Cookie от других - не сказано. Однако, есть интересный параграф:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;   The user agent will reject cookies unless the Domain attribute
   specifies a scope for the cookie that would include the origin
   server.  For example, the user agent will accept a cookie with a
   Domain attribute of &quot;example.com&quot; or of &quot;foo.example.com&quot; from
   foo.example.com, but the user agent will not accept a cookie with a
   Domain attribute of &quot;bar.example.com&quot; or of &quot;baz.foo.example.com&quot;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Но, вроде, не про то. У нас то сам api.tapcat.net хочет проставить Сookie для api.tapcat.net.&lt;/p&gt;

&lt;p&gt;Второй документ находится в состоянии Candidate Recommendation и ничего про нашу ситуацию не говорит.&lt;/p&gt;

&lt;p&gt;А про механизм определения third-party-cookies - вообще засада. Нигде нет его описания. Помогите мне его найти!
4 дня искал и не нашел. Даже смотрел исходный код Firefox. Но, ссылок на стандарт там нет. Поиски продолжаются.&lt;/p&gt;

&lt;p&gt;И, да. В результате удалось отделить статику от сервера с бизнес логикой на уровне доменов. Как Я и хотел. ;)&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/cors-and-thirdparty-cookies/&quot;&gt;CORS and Third-Party Cookies&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 17, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Docker OpenVPN]]></title>
  <link rel="alternate" type="text/html" href="/blog/docker-openvpn/" />
  <id>/blog/docker-openvpn</id>
  <published>2013-10-06T00:00:00+00:00</published>
  <updated>2013-10-06T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;На днях дома отключился интернет. Оказалось, что к провайдеру пришли правохраниетльные органы и забрали сетевое оборудование. Перевел весь домашний трафик через Голландию. Чтоб неповадно было. Сейчас расскажу как.
Для понижения уровня паранои нам потребуются:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/?refcode=06c4ef09e5cc&quot;&gt;Сервер за границей&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.docker.io/&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;section&quot;&gt;Сервер&lt;/h2&gt;
&lt;p&gt;Нужна машина с 256мб ОЗУ. Ничего сверхестественного.
Порекомендовать могу &lt;a href=&quot;https://www.digitalocean.com/?refcode=06c4ef09e5cc&quot;&gt;DigitalOcean&lt;/a&gt;.
5$ в месяц. Все сервера на SSD. Быстрый хелпдеск. Вот моя ссыль: &lt;a href=&quot;https://www.digitalocean.com/?refcode=06c4ef09e5cc&quot;&gt;DigitalOcean&lt;/a&gt;.
А еще и докер ставится в один клик. Оооочень просто.
В один клик
&lt;img src=&quot;/images/docker/digital-ocean-docker.png&quot; alt=&quot;Docker VM provisioning&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;/h2&gt;
&lt;p&gt;Docker - обертка над lxc контейнерами. Если просто - то это инструмент, позволяющий быстро создавать и управлять сверхлегкими виртуальными машинами.&lt;/p&gt;

&lt;p&gt;Зачем именно Docker? Можно было развернуть OpenVpn сервер прямо на виртуальной машине.
Ответ прост. В результате удалось получить контейнер с установленным OpenVPN, который Я могу переносить с машины на машину и запускать одной командой. Никакой донастройки!&lt;/p&gt;

&lt;p&gt;Докер мне попался на глаза, как только Я решил сделать Continues Delivery для нового проекта.
CD сделал. Скоро напишу об этом.&lt;/p&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;
&lt;p&gt;Начинаем. Для базы выберем образ убунты&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -privileged -i -t ubuntu:precise /bin/bash # i - интерактивный режим. Попадаем в консоль
apt-get install -y iptables wget # iptables - для openVpn; wget - чтобы скачать openVPN AS

# Ставим OpenVPN
wget http://swupdate.openvpn.org/as/openvpn-as-1.8.5-Ubuntu12.amd_64.deb
dpkg -i openvpn-as-1.8.5-Ubuntu12.amd_64.deb

# tun утсройства в контейнере нет, но ведь оно прокинуто снаружи. Создадим его руками
mkdir -p /dev/net
mknod /dev/net/tun c 10 200

# ставим пароль админа и запускаем сервис
passwd openvpn
/etc/init.d/openvpnas start

# создаем пользователей. OpenVPN их подцепит
useradd borov
passwd borov

exit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Готово. Осталось сохранить контейнер.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Самый верхний ID - это наш
docker ps -a

docker commit $ID -t borov/openvpn
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Образ готов.
Запускаем&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  docker run -d -privileged -p 1194:1194/udp -p 443:443/tcp -p 943:943/tcp -t borov/openvpn-server /bin/bash -c &quot;service openvpnas start &amp;amp;&amp;amp; tail -f /var/log/openvpnas.log&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Готово! Теперь по адресу &lt;code&gt;https://your-vm.com/&lt;/code&gt; откроется консоль OpenVPN через которую можно подключиться к сети или зайти с административного аккаунта.
И больше никаких настроек!&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/docker-openvpn/&quot;&gt;Docker OpenVPN&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 06, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Reactive]]></title>
  <link rel="alternate" type="text/html" href="/blog/reactive-programming/" />
  <id>/blog/reactive-programming</id>
  <published>2013-10-03T00:00:00+00:00</published>
  <updated>2013-10-03T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Ох, приехали. Даже в вакансии DB сегодня Я обнаружил “Experience in UI architecture (MVP, reactive programming)”
Scala в содружестве с TypeSafe всетаки продвинули еще одно слово паразит в массы.
Теперь все, до чего дотрагиватется TypeSafe начинает называться Reactive. Даже курс на курсере решили назвать Reactive Programming.
Cloud, Big Data….. теперь еще и Reactive. Ну ребята. Ну прекратите.
Особенно поразило то, что слова паразиты влезли в описание вакансий.
А ведь это всего лишь название одного из паттернов&lt;/p&gt;

&lt;h2 id=&quot;reactor&quot;&gt;Reactor&lt;/h2&gt;
&lt;p&gt;Паттерн. Используется для построения асинхронных приложений. Больше прочитать можно в &lt;a href=&quot;http://en.wikipedia.org/wiki/Reactor_pattern&quot;&gt;ВикиПедии&lt;/a&gt;.
Примерами могут являться NodeJS и Twisted.
Также есть интересная статья, датированная 2010 готом от самого Мартина-Мартина, показывает нам новый подход к написанию интерактивных приложений. Подход - именно Reactor. Вот статья: &lt;a href=&quot;http://lampwww.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf&quot;&gt;Deprecating Observer&lt;/a&gt;.
Подход не новый. И особо ничего уникального для языков с поддержкой Continuation нет. Но, прочитать стоит.
На этом хорошие новости заканчиваются. До текущего времени в Scala идея не получила развития (&lt;a href=&quot;http://www.scala-lang.org/old/node/10865.html&quot;&gt;scala.react&lt;/a&gt;).
Даже репозиторий с черновой реализацией на Гитхабе заброшен.
Теперь о TypeSafe. В основном продукте компании используется подход с использованием паттерна Reactor. Наравне с другими паттернами.
Но, кто же решил, что Reactor - самый смак?&lt;/p&gt;

&lt;h2 id=&quot;section&quot;&gt;Маркетологи&lt;/h2&gt;
&lt;p&gt;Люди, подарившие нам Cloud, Big Data, Rich Client не сидят на месте. Вот оно, наше будущее: Reactive. Если в вашей компании вы не Reactive, то вы не в тренде. Блог TypeSafe постоянно на это намекает.
Новый релиз Play Framework носит сияющий шильдик ‘Reactive’. И это не мажорный релиз.
Spring Reactor - фреймворк для написания асинхронных приложений на JVM. Кто повлиял на название?&lt;/p&gt;

&lt;h2 id=&quot;section-1&quot;&gt;Вывод&lt;/h2&gt;
&lt;p&gt;Я очень бешусь от того, что вокруг меня начали употреблять слово Reactive направо и налево.
Возможно, это надуманно. Помогите разобраться.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/reactive-programming/&quot;&gt;Reactive&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 03, 2013.&lt;/p&gt;</content>
</entry>


  

<entry>
  <title type="html"><![CDATA[Firefox OS phone]]></title>
  <link rel="alternate" type="text/html" href="/blog/firefox-phone/" />
  <id>/blog/firefox-phone</id>
  <published>2013-10-02T00:00:00+00:00</published>
  <updated>2013-10-02T00:00:00+00:00</updated>
  <author>
    <name>Denis Golovachev</name>
    <uri></uri>
    <email>denis@borov.net</email>
  </author>
  <content type="html">&lt;p&gt;Сегодня с утра Я открыл почту и удивился. Mozilla пришлет мне телефон.
Похоже, что следующее приложение для Firefox OS не за горами ;)&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;/blog/firefox-phone/&quot;&gt;Firefox OS phone&lt;/a&gt; was originally published by Denis Golovachev at &lt;a href=&quot;&quot;&gt;Post-Engineering&lt;/a&gt; on October 02, 2013.&lt;/p&gt;</content>
</entry>

</feed>