Блог о Gentoo и около-линуксовым штукам

10 апреля 2018 г.

NoWOL: питание ПК через интернет. Часть 2.

5:55 Опубликовал Дмитрий Исаенко , , Нет комментариев
Продолжаем! Для проекта NoWOL есть Android-приложение с виджетом.

Вообще, там всё весьма просто. Как будет возможность (не лень), загружу исходники в GitHub. Пока же там лежит вполне готовая к использованию APK'шка.
Из ключевых моментов: внутри используется библиотека Volley; работает приложение под Android 4.0 и выше (minSdkVersion 14, target 26).

Архитектура проста донельзя. Приложение отправляет HTTP-запросы по указанному адресу и парсит ответы.

А теперь скриншоты!

После установки станет доступно основное приложение, а в разделе виджетов появится новый виджет с одноимённым названием «NoWOL».

Что касается приложения, то в нём доступно несколько состояний: неизвестно, онлайн, офлайн, нет ответа (от хоста). Обновить состояние можно нажав на кнопочку в верхней панели.


Если нажать на шестерёнку на верхней панели, всплывёт окно для указания IP хоста в сети. Следует обратить внимание на формат записи. Защиты от дурака там, к сожалению, не так много как хотелось бы. Вот хороший пример:

  

При добавлении виджета появится окно конфигуратора. Как видно, в нём нет указателя на адрес хоста. Он настраивается внутри приложения, поэтому сперва стоит запустить его.
Зато в конфигураторе можно выбрать задний фон (белый или чёрный) с альфа-каналом и уровень его прозрачности.
UI немного неочевиден и меняется в зависимости от выбора "галочки". Я знаю, так делать нехорошо.
 

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

Забавный момент: если ПК в режиме ожидания, то статус будет или "онлайн" или "офлайн" в зависимости от того, мигнула ли лампочка в момент запроса состояния :)

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


В общем-то на этом всё. Надеюсь, вам понравилось =)

NoWOL: питание ПК через интернет. Часть 1.

4:28 Опубликовал Дмитрий Исаенко , , , Нет комментариев
Ох, давно хотел уже задокументировать это здесь, да всё времени не было. И вот, спустя полтора года…

Какую проблему решаем?

Стоит задача включать и выключать ПК нажимая на кнопки включения\выключения и сброса не руками, а через интернет (ну или через тоннель в интранет). В идеале спросонья через виджет в телефоне а-ля узнал погоду за бортом, включил ПК и можно идти ставить кофе.

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

Немного покопавшись я решил закупить основанную на enc28j60 приблуду для ардуины, а заодно и саму ардуину. Изучив особенности программирования enc28j60 руками (без высокоуровневых IDE и готовых библиотек) и бегло осмотрев errata, который, надо отметить, чуть ли не больше даташита, стало ясно, что на низком уровне рулить “этим” сущий ад и боль. Поэтому, будем собирать всё на базе добротного китайского клона Arduino nano или функционального аналога (лучше просто взять arduino, правда).

В итоге система будет состоять из основного модуля в виде связки Arduino+enc28j60 и выносного блока с оптопарами и резисторами.

В целом выглядеть и подключаться всё будет так:

Но перед тем, как начать…

Поставим себе пару пакетов:
1. dev-embedded/arduino
2. sci-electronics/eagle (ветка 7.x.x и лучше из нестабильной ветки) 
Все необходимые файлы лежат в проекте на GitHub:
https://github.com/developersu/NoWOL

Про выносной модуль

Файлы для Eagle CAD находятся в директории eagle_files/m2Board/ .
Необходимые библиотеки в eagle_files/lib/ .

Для выносного модуля понадобится:

Part Value Device Package Library Sheet
IC2 КР293КП4А DIL08 ic-package 1
IC3 КР293КП4А DIL08 ic-package 1
IN PINHD-1X6 1X06 pinhead 1
OUT PINHD-1X6 1X06 pinhead 1
R1 450Ω или 470Ω R-EU_0204/5 0204/5 resistor 1
R2 450Ω или 470Ω R-EU_0204/5 0204/5 resistor 1
R3 330Ω R-EU_0204/5 0204/5 resistor 1
TO_MCU PINHD-1X5 1X05 pinhead 1

По-поводу R1 и R2 резисторов, я собрал две пары, чтобы получилось 450 Ом в каждой. Думаю, что если взять просто пару штук на 470 Ом всё тоже будет работать. Но всё же обещать не буду.

Его принципиальная схема выглядит весьма просто:

Разводка выполняется на односторонней плате:


* 'cuz soviet works better
Если присмотреться, разводка слегка отличается от той, что приведена на первом рисунке. Тут я убрал перемычку.

Как вы уже поняли, в качестве оптопар используется отечественная схема КР293КП4А в корпусе DIP8. Внутри каждой микросхемы находится 2 оптопары. Одна из схем замыкает и размыкает кнопки (питание и сброс), а вторая говорит микроконтроллеру включена ли система, определяя это по светодиоду-индикатору питания. Если первую микросхему замыкает МК, то вторую — ПК. Через отдельный пин микроконтроллер зажигает индикатор питания сам, когда понимает, что и система (ПК) тоже его зажгла. Уж не знаю.. может это несколько избыточно и можно было сделать проще. Впрочем, получилось как получилось.

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

Если всё спаять и приправить должным количеством пыли, получится примерно следующее:


Про программирование Arduino

Теперь перейдём к программированию Arduino. Как говорилось ранее, предполагается использование Arduino Nano.
Я уже не помню что куда нажимать и подключать, чтобы это дело прошить но у меня есть скетч!
Для этого скетча понадобится библиотека ehtercard. И скетч и библиотека находятся в директории arduino_sketchbook/.

А вот и сам код:
#include <EtherCard.h>

#define PWR_PIN 6
#define RST_PIN 7
#define PWR_LED_IN 8
#define PWR_LED_OUT 5


int i;
// Зададим MAC адрес устройства
static byte mymac[] = { 0xDE,0xAD,0xBE,0xEE,0xEE,0xEF };
 
// Чем больше данных отображается на странице, тем больше требуется буфер для них
byte Ethernet::buffer[900];
BufferFiller bfill;
 
//Массив задействованных контактов для управления оптопарами
int LedPins[] = {PWR_PIN,RST_PIN};
 
//Массив для фиксации изменений
boolean PinUpdate = 0;      //100-reset 200-power 5050-powerOFF
 
const char http_OK[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n\r\n"
"\r\n"
"<html>"
  "<head><title>"
    "noWOL"
  "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><style>"
  "body { font-family: monospace;\n"
   "background-color: #000000;\n"
   "font-size: 30px;\n"
   "font-weight: bold;\n"
   "color: #b2b2b2;}\n"
   "a:link, a:visited {  display: inline-block;\n"
  "color: #b2b2b2;\n"
  "font-weight: 700;\n"
  "text-decoration: none;\n"
  "padding: .3em 2em;\n"
  "outline: none;\n"
  "border: 2px solid;\n"
  "border-radius: 15px;\n"
  "transition: 0.2s;}\n"
  "a:hover {color: #fefefe;}\n"
  "</style></head>"
  "<body><center>"
;
const char http_Found[] PROGMEM =
"HTTP/1.0 302 Found\r\n"
"Location: /\r\n\r\n";

const char http_Unauthorized[] PROGMEM =
"HTTP/1.0 401 Unauthorized\r\n"
"Content-Type: text/html\r\n\r\n"
"401 Unauthorized";
 
void homePage()
{
bfill.emit_p(PSTR("$F"
  " "
  "$F<p>"
  "<a href='?RESET=on'>  RESET   </a><p>"  //D6
  "<a href='?POWER0=on'>  POWER   </a><p>" //D7 short
  "<a href='?POWER1=on'>POWER 5sec</a><br />"),  //D7 long
  //"PWR LED out D5 : $F <br /></body></html>"),
  
  http_OK,
  (digitalRead(PWR_LED_IN) == HIGH)?PSTR("<span style=\"color: #AA0000\">          ▄▄▄▄▄▄</span>"):PSTR("<span style=\"color: #00c600\">          ▄▄▄▄▄▄</span>")),//⬤
//  (bitRead(PORTD,PWR_LED_OUT) == HIGH)?PSTR("HIGH"):PSTR("LOW")),

"</center></body>"
"</html>"
  ;
}

void pick_pin(int pin, int del) {
      digitalWrite(pin,HIGH);
        delay(del);
        digitalWrite(pin,LOW);
        PinUpdate = 0;
}
 
void setup()
{
// SET UART
//  Serial.begin(9600);
//Change default ethercard CS - pin 8 to 10
  //if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)

//  Serial.println( "Access to Ethernet controller failed");
    ether.begin(sizeof Ethernet::buffer, mymac, 10);
    ether.dhcpSetup();
//  if (!ether.dhcpSetup())
//       Serial.println("DHCP routine failed");
    //Print over UART configuration recieved:
//  ether.printIp("IP:  ", ether.myip);          
//  ether.printIp("GW:  ", ether.gwip);  
//  ether.printIp("DNS: ", ether.dnsip);  

  for(i = 0; i < 2; i++) {
    pinMode(LedPins[i],OUTPUT);
  }
  
    pinMode(PWR_LED_OUT,OUTPUT);
    pinMode(PWR_LED_IN,INPUT_PULLUP); // LED-питания как вход
}
 
void loop()
{
    delay(1);

        if (digitalRead(PWR_LED_IN) == HIGH) {        // если мать выключена
            if (bitRead(PORTD,PWR_LED_OUT) == HIGH) digitalWrite(PWR_LED_OUT,LOW);
        }
        else if (bitRead(PORTD,PWR_LED_OUT) == LOW) {
          digitalWrite(PWR_LED_OUT,HIGH);
        }

        switch (PinUpdate) {
          case 0:
            break;
          case 1:
            pick_pin(RST_PIN, 200);
            break;
          case 2:
            pick_pin(PWR_PIN, 200);
            break;
          case 3:
            pick_pin(PWR_PIN, 5050);
            break;
        }

    word len = ether.packetReceive(); //Проверить ethernet пакеты
    word pos = ether.packetLoop(len); //Проверить TCP пакеты
    if (pos) {
        bfill = ether.tcpOffset();
        char *data = (char *) Ethernet::buffer + pos;
        if (strncmp("GET /", data, 5) != 0) {
            bfill.emit_p(http_Unauthorized);
        }
        else {
            data += 5;
            if (data[0] == ' ') {
                    homePage(); //Если обнаружено изменения на станице, то запускаем функцию
            }
            //"10" = количество символов "?RESET=on ".
            else if (strncmp("?RESET=on ", data, 10) == 0) {
                bfill.emit_p(http_Found);
                                PinUpdate = 1;
            }
 
            else if (strncmp("?POWER0=on ", data, 11) == 0) {
                  bfill.emit_p(http_Found);
                                PinUpdate = 2;
            }
 
            else if (strncmp("?POWER1=on ", data, 11) == 0) {
                    bfill.emit_p(http_Found);
                                PinUpdate = 3;
            }

            else {
                //Страница не найдена
                bfill.emit_p(http_Unauthorized);
            }
        }
        ether.httpServerReply(bfill.position());
    }
}
Теперь, когда всё что надо прошито, соединяем как указано на рисунке в начале публикации и подключаем это дело к сети. На машрутизаторе должен быть настроен DHCP сервер.
Мак-адрес нового устройства, как ясно из исходного кода, будет de:ad:be:ee:ee:ef. Лучше сразу назначить постоянную аренду. В OpenWRT с LuCI идём в:
«Сеть» → «DHCP и DNS» → вкладка «Основные настройки» → «Постоянные аренды» → «Добавить».
Пишем там как показано на рисунке:


Когда всё настроено и подключено, заходим на адрес http://192.168.1.100 и видим следующее:


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

То, что всё это находится в интрасети и не отсвечивает в мир меня вполне устраивает, ведь при подключении по VPN доступ появляется и в Android-приложении и через WEB-интерфейс. Ах да! Для всего этого дела есть ещё и Android-приложение :) Но о нём во второй части.

Вредные советы

Как бы не использовать Arduino?

Лучше таки его использовать.
Но можно и спаять свою ардуину, с блекджеком и профусетками, чтобы она была поменьше и конкретно под этот проект.
Сразу оговорюсь, я наделал кучу ошибок и паял отдельные костыли чтобы всё сошлось.. потом переделал схему, потом ещё пару раз, и уже не помню на сколько там правильная разводка. Так что лучше внимательно изучить и прислать мне фидбек в виде линки на исправленную версию. Или апробировать, если всё правильно =)

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

Находится всё в директории eagle_files/atmegaBoard/ .

Список компонентов:

Part Value Device Package Library Sheet
C1 22pF C-EUC0603 C0603 resistor 1
C2 22pF C-EUC0603 C0603 resistor 1
C3 10uF CC0603 C0603 eagle-ltspice 1
C4 22uF CC0603 C0603 eagle-ltspice 1
IC1 atmega328p atmega328p TQFP32-08 avr-6 1
IC3 LM1117IMPX-3.3 LM1117IMPX-3.3 SOT223 lm1117 1
JP1
PINHD-2X5 2X05 pinhead 1
JP3 PINHD-1X2 1X02 pinhead 1
Q1 16MHz XTAL/S QS special 1
SV1 MA05-1 MA05-1 con-lstb 1
U1 USB"" USB-MICRO-SMD MicroUSB 1

Схема принципиальная:


Сама разводка:


Что тут добавить.. земля на гребёнке справа. JP3 нужен для прошивки схемы. Прошивается она через Arduino IDE.. Кажется с помощью самой ардуины. Ну или через USBasp программатор. В общем, главное ничего не перепутать. А настройки должны быть вроде таких:

1)
 

2)


В следующей части будет обзор Android-приложения. APK файл находится в папке Android_APK.

Итого

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



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

--
Особая благодарность Unyuu за неоценимый вклад. Во многом благодаря его советам этот проект стал возможен.


Лицензия Creative Commons
Текстовый материал распространяется по лицензии Creative Commons С указанием авторства-Некоммерческая-С сохранением условий 4.0 Всемирная.
Обратите внимание: это ограничение не касается графических изображений и исходного кода. Если на самом изображении не указано иного, они доступны по лицензии Creative Commons С указанием авторства 4.0 Всемирная.

22 марта 2018 г.

О ретрекерах rutracker @ OpenWRT

3:55 Опубликовал Дмитрий Исаенко Нет комментариев
В роли заметки.
Чтобы в торрентах, скачаных с rutracker получать списки скачивающих/раздающих хорошо бы иметь доступ к ретрекерам. Их не так уж и много:
bt.t-ru.org
bt2.t-ru.org
bt3.t-ru.org
bt4.t-ru.org
Заодно с этим и статистика розданного начнёт учитываться. Доступ к ним можно получить просто перенаправляя трафик, адресованый ретрекерам через прозрачную проксю.
Для этого в OpenWRT LuCI заходим в СетьМежсетевой экранCustom Rules и добавляем всего одну строку.
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -d 195.82.146.120/30 -j DNAT --to-destination 163.172.167.207:3128

Сохраняем, применяем. Всё!

mplayer4anime

3:25 Опубликовал Дмитрий Исаенко , , Нет комментариев
mplayer4anime — это фронт-энд к плееру mplayer. Если ищите удобный способ запускать mkv и mka одновременно — это как раз оно!
Задача проста, заменить bash-скрипты для запуска связок mkv+mka+субтитров. Почему это нужно? Ну, например, чтобы продолжать раздавать торренты в том виде, в котором они были скачаны. Конечно, в интересах удобства сразу в голову придёт идея объединить mkv и mka в один контейнер используя mkvmerge, но тогда не получится посидеть на раздаче или придётся жертвовать свободным местом на диске.

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

GUI, ня!


Системные требования: JRE-1.8 (8) или выше.
Протестировано в Gentoo (virtual/jre 1.8.0-r1) и Debian Stretch (стандартный образ + openjfx).

Лицензия: GNU GPL v3.
Пиктограммы: material design.
Прочая графика: работы находящиеся в общественном достоянии или распространяющиеся по лицензии CC0 + собственные работы.

Версия на данном этапе вполне рабочая, но некоторые экстра-плюшки всё ещё не реализованы, например drag-n-drop.

И ещё, работает всё именно с mplayer а не с mpv или smplayer (хотя хотелось бы), так что подучите команды mplayer (f - полноэкранный режим, enter - закрыть, пробел - пауза).
Линка: https://github.com/developersu/mplayer4anime

Ах да, в будующих релизах будет добавлена поддержка Windows и, вероятно, безшовный запуск (отдельно устанавливать javaFX/JRE не потребуется). На macOS должно и так работать. Скажите мне если вдруг решитесь попробовать!

Ооо.. вот ещё, если вам вдруг понравилось, оставьте коммент! А даже если не понравилось, то тоже можно =)

7 марта 2018 г.

Deban stretch: возвращаем старые имена сетевых интерфейсов

7:34 Опубликовал Дмитрий Исаенко Нет комментариев
После загрузки systemctl status показывал мне статус degraded. Хотелось разобраться, что ему не нравится. Как оказалось, проблема была в именах сетевых интерфейсов которые генерировались автоматически. Что же, настало время венуть привычные вместо enp0s1 и т.п.
Приступим!

# systemctl status
...
    State: degraded
...

# systemctl
...
networking.service    loaded failed failed    Raise network interfaces
...
Исправляем добавив правило в udev.
# vim /etc/udev/rules.d/10-rename-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="ff:ff:ff:ff:ff:ff", NAME="eth0"
Теперь исправим наши настройки автозагрузки поменяв имя интерфейса:
# vim /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
allow-hotplug eth0
iface eth0 inet dhcp
И после перезагрузки всё будет как надо!

1 марта 2018 г.

Заметки о вытаскивании дорожек из mkv и создании mka

0:50 Опубликовал Дмитрий Исаенко , Нет комментариев
Есть задача — вытащить аудио-дорожку из одного mkv файла и сделать из неё mka файл. Таким образом можно было бы использовать экспортированный дубляж в другом, более качественном видео-файле. Итак, нам понадобится mkvtoolnix. Ставим:
# emerge media-video/mkvtoolnix
Далее получаем информацию о файле-доноре. В нём ищем информацию о звуковых дорожках внутри матрёшки.
$ mkvinfo ./anime.mkv
+ Заголовок EBML
|+ Версия EBML: 1
...
...
| + Дорожка
|  + Номер дорожки: 2 (идентификатор дорожки для mkvmerge и mkvextract: 1)
|  + UID дорожки: 16263157260285453471
|  + Тип дорожки: audio
|  + Идентификатор кодека: A_MPEG/L3
|  + Продолжительность по умолчанию: 24.000ms (41.667 кадров/полей в секунду для видеодорожки)
|  + Язык: und
|  + Audio track
|   + Частота дискретизации: 48000
|   + Каналы: 2
|+ EbmlVoid (размер: 1095)
|+ Кластер
Тут важно обратить внимание на то, что подсвечено красным. В данном примере используется mp3 файл который имеет идентификатор 1 для mkvextract. Сейчас мы этим и воспользуемся. Вытаскиваем аудиодорожку в файл file.mp3.
$ mkvextract tracks ./anime.mkv 1:file.mp3
Извлечение дорожки 1 с CodecID 'A_MPEG/L3' в файл 'file.mp3'. Формат контейнера: MPEG-1 Audio Layer 2/3
Обработано: 100%
Теперь воспользуемся GUI обёрткой над mkvtoolnix (mkvtoolnix-gui). Вы же собрали пакет с флагом qt5, верно? ;)
Выбираем файл (правой кнопкой клик на поле «Исходные файлы». Далее ставим нужный язык в одноимённом поле и жмём «Выполнить сборку».
На выходе получаем mka-файл. В моём случае подгонка по таймлайнам не требовалась, так что всё сразу заработало.

На этом всё!

19 января 2018 г.

Почему вы не сможете запустить своё Аvito (если вы не mail.ru group)

8:44 Опубликовал Дмитрий Исаенко Нет комментариев
Российский рынок — прекрасная площадка для вашего нового бизнеса. Очевидно, что на нём есть масса незанятых нишей. Рассмотрим на примере успеха avito. Компания заняла ту позицию, которую на западном рынке традиционно занимает ebay. Что не так с ebay в России? Да всё просто. Она всеми силами пытается не быть нацеленной на этот рынок. Просто посмотрите что пишут продавцы в графе доставки — куда угодно по миру, только не к нам. И не в Бразилию. И не в %подставьте пару исключений из любого списка, ведь они повторяются%. Почему так происходит — совсем другой вопрос не касающийся данной заметки. Отбросим также все нюансы связанные с тем, что это всё же аукцион(!). Забудем пока и про особенности пользовательского интерфейса, привычки к расположению элементов также, пусть не сильно, но разнятся.

Итак у нас есть запрос на площадку по продаже всего. В целом, это можно даже вписать в парадигму того, что именуется как “e-commerce“. Что нужно рынку? Просто предоставить такую площадку и дать мощную рекламу со всех щелей. При этом не столь важно на сколько будет хороша такая площадка, важна именно огласка и быстрый захват рынка. Когда рынок захвачен — остаётся лишь удержать его от возможных конкурентов. И когда Вася Пупкин решает что avito полная дрянь с точки зрения условий пользовательского соглашения/ущемляет права приволжских уточек и думает (ключевое тут именно «думает»), что может сделать лучше он попадает в очень мерзкое положение. Вася строит свой сайт, пишет свой движок, запускается на модном nodejs и вот уже готовый продукт который… никому не нужен. Просто потому, что у Васи не осталось денег на раскрутку. Он начинает думать что в его продукте что-то не так, поэтому не идут продавцы. Если там некому продавать, не идут клиенты. И, на этом можно заканчивать. Аvito узнает о таком конкуренте только если он напишет им письмо.

С другой стороны какая-нибудь Юла (привет mail.ru) с кучей денег на рекламу, аналитическим отделом и начинает совершенно с другого конца. Будучи большой компанией, запуская конкурента она может позволить себе инвестировать большие суммы в рекламу не имея вообще никакого продукта и даже не имея проектной документации (Вася пупкин врядли вообще задумывался о её существовании). Подогревая интерес на протяжении нескольких месяцев к грядущему «убийце айфона avito» они делают свой продукт о котором заранее известно будущей аудитории. В деревне солнечного Алтая тракторист Лаврентий уже знает где, если что, он будет искать запасные болты для своего УАЗа. В итоге, mail.ru подготовив мягкую подстилку для выхода на рынок и имея чёткое представление о предпочтениях пользователей подобных площадок (спасибо за бесплатную аналитическую работу, проведённую за них тем-же avito) они выпускают собственную Юлу. Тадам-с! Эффект взрывающегося вертолёта создан. Далее продавцы и покупатели тянуться к ним т. к. есть монополист и свежеиспечённый распиареный сервис, альтернатив по масштабу которому просто нет. Да, в реальности, то, что представляет собой «Юла» на старте это просто пустая площадка, такая же как у нашего Васи. Только о Васе так никто и не узнал.

И вот вы решили что это всё достаточно очевидно, и вообще, «я просто хочу сделать сервис по ремонту зажигалок и занять пустующую нишу! Моих надцати тысяч будет достаточно!». И.. нет. Вероятнее всего не будет. Пусть вы вложились в рекламу, имеете бета-релиз (гы, бета-релиз) и начинаете ждать покупателей. Что происходит дальше? У вас заканчиваются деньги, вы работаете за счёт проданной машины ещё пару месяцев в течении которых вас 1. могут купить как хороший стартап (свой бизнес это свой бизнес, но пятьдесят баксов это пятьдесят баксов) или 2. один из гигантов просто запускает вам конкурента вложив ещё больше денег в пиар даже не имея ничего.

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