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

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вс окт 30, 2022 20:34:58

Понятно что декодировать mp3-поток (по причине закрытости протокола) придется готовыми микросхемами-декодерами типа VLS1053.
Это неверное утверждение. http://we.easyelectronics.ru/STM32/prog ... zvuki.html
Ойё. Вот это сюрприз. Не знал категорически. Большущее мурси. Будем поглядеть.

Добавлено after 33 minutes 46 seconds:
сайт https://www.internet-radio.com/search/?radio=shoutcast работает по протоколу HTTPS...

download/file.php?id=380314

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

алгоритм Диффи-Хеллмана на эллиптических кривых, аутентификация сервера будет производится с помощью ECDSA, а в качестве алгоритма шифрования трафика будет использоваться AES с длиной ключа 128 бит в режиме GCM. В качестве алгоритма MAC используется SHA256.

Прикольно))
:))
И на чём вы это всё собрались делать ? ))
:tea:
Если вы ко мне - то я не собирался. я делал. Работало вполне успешно. См. начало ветки..

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вс окт 30, 2022 20:50:51

Ariadna-on-Line, 5 лет назад патент прекратился, так что, теперь можно даже продавать официально без отчислений, если вдруг эта разработка станет коммерческой

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вс окт 30, 2022 23:29:18

я не собирался. я делал. Работало вполне успешно. См. начало ветки..

начало ветки...
:roll:
это чтоль...
Arduino-WebRadio-player-master.zip
так там обычный список IP...
там поток работает по обычному TCP )) без шифрования !!!!
IP.jpg
(64.87 KiB) Скачиваний: 50

roman.com писал(а):сайт https://www.internet-radio.com/search/?radio=shoutcast работает по протоколу HTTPS...

download/file.php?id=380314

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

алгоритм Диффи-Хеллмана на эллиптических кривых, аутентификация сервера будет производится с помощью ECDSA, а в качестве алгоритма шифрования трафика будет использоваться AES с длиной ключа 128 бит в режиме GCM. В качестве алгоритма MAC используется SHA256.

Прикольно))
:))
И на чём вы это всё собрались делать ? ))
:tea:

:)))
да нет там никакого TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

там поток работает по обычному TCP )) без шифрования !!!!
интернет радио.jpg
(192.88 KiB) Скачиваний: 49

там все потоки работает по обычному TCP )) без шифрования !!!!
интернет радио_2.jpg
(184.82 KiB) Скачиваний: 59

подключаемся и слушаем...
:tea:

а то я уже волноваться начал... думаю... неужели Ардуина научилась шифровать поток.... на лету))
:shock:
https://www.radiokot.ru/forum/download/ ... ?id=381163

а там всё просто оказывается))
:sleep:

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вс окт 30, 2022 23:58:57

а там всё просто оказывается))
Медиа-контент. Зачем его шифровать ?! По секрету всему свету )))))) Вот пример из библиотеки к шильду -
SFEMP3Shield MP3player. Типа музыкальный сервер. Коль под Ардуину заточен, значит не так уж там и сложно.
Код:
/**
 * \file WebPlayer.ino
 *
 * \brief Example sketch of using the MP3Shield Arduino driver to create a webserver
 * \remarks comments are implemented with Doxygen Markdown format
 *
 * \author Michael P. Flaga
 * \author AdaFruit
 *
 * This sketch is a quick merge of http://github.com/adafruit/SDWebBrowse with
 * SFEMP3Shield library demonstrating the VS1053 commanded through a web browser.
 *
 * \warning
 * Need to set the following in the SFEMP3ShieldConfig.h, in order to work.
 * \code #define USE_MP3_REFILL_MEANS USE_MP3_Polled \endcode
 * as the Ethernet library makes interrupts not possible.
 * any one with a fix, let me know.
 */

#include <SdFat.h>
#include <FreeStack.h>
#include <Ethernet.h>
#include <SPI.h>

// Below is not needed if interrupt driven. Safe to remove if not using.
#if defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_Timer1
  #include <TimerOne.h>
#elif defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer
  #include <SimpleTimer.h>
#endif

#include <SFEMP3Shield.h>

//create and name the library object
SFEMP3Shield MP3player;
byte result;

/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//byte ip[] = { 192, 168, 0, 79 };
byte ip[] = { 172, 17, 67, 192 };
EthernetServer server(80);

/************ SDCARD STUFF ************/
SdFat sd;
SdFile file;

//----------
/**
 * \brief Setup the Arduino Chip's feature for our use.
 *
 * After Arduino's kernel has booted initialize basic features for this
 * application, such as Serial port and MP3player objects with .begin.
 */
void setup() {
  Serial.begin(115200);

  Serial.print(F("Free RAM: "));
  Serial.println(FreeStack());

  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH);                    // but turn off the W5100 chip!

  pinMode(8, OUTPUT);
  digitalWrite(8, LOW); // put VS1053 into reset

  if(!sd.begin(9, SPI_HALF_SPEED)) sd.initErrorHalt();
  if (!sd.chdir("/")) sd.errorHalt("sd.chdir");

  Serial.print(F("Volume is FAT"));
  Serial.println(sd.vol()->fatType(),DEC);
  Serial.println();

  // list file in root with date and size
  Serial.println(F("Files found in root:"));
  sd.ls(LS_DATE | LS_SIZE);
  Serial.println();

//  // Recursive list of all directories
//  Serial.println(F("Files found in all dirs:"));
//  sd.vwd()->ls(LS_R);
//  Serial.println();

  Serial.println(F("Done"));

  // Debugging complete, we start the server!
  Ethernet.begin(mac, ip);
  server.begin();

  result = MP3player.begin();
  //check result, see readme for error codes.
  if(result != 0) {
    Serial.println(F("Error code: "));
    Serial.print(result);
    Serial.println(F(" when trying to start MP3 player"));
    }
  MP3player.setVolume(80,80); // commit new volume  Serial.println(FreeRam());

}

//----------
/**
 * \brief dump list of files to the web
 *
 * The SdFat does not have an easyway to go down the list of files and get there
 * names for direct handeling. Hence this does that.
 */
void ListFiles(EthernetClient client, uint8_t flags) {
  // This code is just copied from SdFile.cpp in the SDFat library
  // and tweaked to print to the client output in html!
  dir_t p;

  sd.vwd()->rewind();
  client.println(F("<ul>"));
  while (sd.vwd()->readDir(&p) > 0) {
    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) break;

    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

    // print any indent spaces
    client.print(F("<li><a href=\""));
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print((char)p.name[i]);
    }
    client.print(F("\">"));

    // print file name with possible blank fill
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print((char)p.name[i]);
    }

    client.print(F("</a>"));

    if (DIR_IS_SUBDIR(&p)) {
      client.print('/');
    }

    // print modify date/time if requested
    if (flags & LS_DATE) {
       sd.vwd()->printFatDate(p.lastWriteDate);
       client.print(' ');
       sd.vwd()->printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    client.println(F("</li>"));
  }
  client.println(F("</ul>"));
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

//----------
/**
 * \brief Main Loop the Arduino Chip
 *
 * This is called at the end of Arduino kernel's main loop before recycling.
 * And is where the user's serial input of bytes are read and analyzed by
 * parsed_menu.
 *
 * Additionally, if the means of refilling is not interrupt based then the
 * MP3player object is serviced with the availaible function.
 */
void loop()
{
  char clientline[BUFSIZ];
  int index = 0;

// Below is only needed if not interrupt driven. Safe to remove if not using.
#if defined(USE_MP3_REFILL_MEANS) \
    && ( (USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer) \
    ||   (USE_MP3_REFILL_MEANS == USE_MP3_Polled)      )

  MP3player.available();
#endif

  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;

    // reset the input buffer
    index = 0;

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        // If it isn't a new line, add the character to the buffer
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ)
            index = BUFSIZ -1;

          // continue to read more data!
          continue;
        }

        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;

        // Print it out for debugging
        Serial.println(clientline);

        // Look for substring such as a request to get the root file
        if (strstr(clientline, "GET / ") != 0) {
          // send a standard http response header
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println();

          // print all the files, use a helper to keep it clean
          client.println(F("<h2>Files:</h2>"));
          ListFiles(client, LS_SIZE);

        } else if (strstr(clientline, "GET /") != 0) {
          // this time no space after the /, so a sub-file!
          char *filename;

          filename = clientline + 5; // look after the "GET /" (5 chars)
          // a little trick, look for the " HTTP/1.1" string and
          // turn the first character of the substring into a 0 to clear it out.
          (strstr(clientline, " HTTP"))[0] = 0;

          // print the file we want
          Serial.println(filename);

          char *get_arg;
          get_arg = strstr(filename, "?");
          Serial.println(get_arg);
          if (get_arg) {
            get_arg[0] = 0;
            get_arg += 5;
            Serial.println(F("get arg invoked "));
            Serial.println(get_arg);
            Serial.println(filename);
            client.println("HTTP/1.1 204 OK");
            client.println();

            // parse through web page commands

            //PLAY
            if (strstr(get_arg, "PLAY") != 0) {
              result = MP3player.playMP3(filename);
              if(result != 0) {
                Serial.print(F("Error code: "));
                Serial.print(result);
                Serial.println(F(" when trying to play track"));
              }

            // STOP
            } else if (strstr(get_arg, "STOP") != 0) {
              MP3player.stopTrack();

            //PAUSE
            } else if (strstr(get_arg, "PAUSE") != 0) {
              if( MP3player.getState() == playback) {
                MP3player.pauseMusic();
                Serial.println(F("Pausing"));
              } else if( MP3player.getState() == paused_playback) {
                MP3player.resumeMusic();
                Serial.println(F("Resuming"));
              } else {
                Serial.println(F("Not Playing!"));
              }

            // VOLUME
            } else if(strstr(get_arg, "VOLUME") != 0) {
              int8_t val = atol(strstr(get_arg, "VAL=") + 4);
              Serial.print(F("Val="));
              Serial.println(val, DEC);

              // push byte[1] into both left and right assuming equal balance.
              MP3player.setVolume(val, val); // commit new volume
              Serial.print(F("Volume changed to -"));
              Serial.print(val>>1, 1);
              Serial.println(F("[dB]"));

            // PLAY SPEED
            } else if(strstr(get_arg, "SPEED") != 0) {
              int16_t val = atol(strstr(get_arg, "VAL=") + 4);
              Serial.print(F("Val="));
              Serial.println(val, DEC);

              MP3player.setPlaySpeed(val); // commit new playspeed
              Serial.print(F("playspeed to "));
              Serial.println(val, DEC);

            }

            //
          } else if (  strstr(strlwr(filename), ".mp3")
             || strstr(strlwr(filename), ".aac")
             || strstr(strlwr(filename), ".wma")
             || strstr(strlwr(filename), ".wav")
             || strstr(strlwr(filename), ".fla")
             || strstr(strlwr(filename), ".mid")
            ) {

            // start of web page
            client.println(F("HTTP/1.1 200 OK"));
            client.println(F("Content-Type: text/html"));
            client.println(F("<html><head></head><body>"));

            client.println();
            client.print(F("<h2>Playing "));
            client.print(filename);
            client.println(F("</h2>"));
            client.println(F("Press back up to see menu."));

            client.println(F("<table>"));
            client.println(F("<tr><td>"));
            ButtonForm(client, "CMD", "PLAY");
            client.println(F("</td><td>"));
//            ButtonForm(client, "CMD", "PAUSE");
//            client.println(F("</td><td>"));
            ButtonForm(client, "CMD", "STOP");
            client.println(F("</table>"));

            client.println(F("<form method=get>"));
            client.println(F("<input type='submit' name='CMD' value='VOLUME'>"));
            client.println(F("<input id='VAL' name='VAL' type='range' min='0' max='100' >"));
            client.println(F("</form>"));

            client.println(F("<form method=get>"));
            client.println(F("<input type='submit' name='CMD' value='SPEED'>"));
            client.println(F("<input id='VAL' name='VAL' type='range' min='1' max='4' value ='1'>"));
            client.println(F("</form>"));

            Serial.print(F("Music file:"));
            Serial.println(filename);

          } else {
            if (! file.open(filename, O_READ)) {
              client.println(F("HTTP/1.1 404 Not Found"));
              client.println(F("Content-Type: text/html"));
              client.println();
              client.println(F("<h2>File Not Found!</h2>"));
              break;
            }

            Serial.println(F("Opened!"));

            client.println(F("HTTP/1.1 200 OK"));
//            client.println(F("Content-Type: text/plain"));
            client.println(F("Content-Type: "));
            Serial.println(F("Content-Type: "));
            if (strstr(strlwr(filename), ".htm") != 0) { //Sets content type.
              client.println(F("text/html"));
              Serial.println(F("text/html"));
            } else if (strstr(strlwr(filename), ".css") != 0) {
              client.println(F("text/css"));
              Serial.println(F("text/css"));
            } else if (strstr(strlwr(filename), ".png") != 0) {
              client.println(F("image/png"));
              Serial.println(F("image/png"));
            } else if (strstr(strlwr(filename), ".jpg") != 0) {
              client.println(F("image/jpeg"));
              Serial.println(F("image/jpeg"));
            } else if (strstr(strlwr(filename), ".gif") != 0) {
              client.println(F("image/gif"));
              Serial.println(F("image/gif"));
            } else if (strstr(strlwr(filename), ".3gp") != 0) {
              client.println(F("video/mpeg"));
              Serial.println(F("video/mpeg"));
            } else if (strstr(strlwr(filename), ".pdf") != 0) {
              client.println(F("application/pdf"));
              Serial.println(F("application/pdf"));
            } else if (strstr(strlwr(filename), ".js") != 0) {
              client.println(F("application/x-javascript"));
              Serial.println(F("application/x-javascript"));
            } else if (strstr(strlwr(filename), ".xml") != 0) {
              client.println(F("application/xml"));
              Serial.println(F("application/xml"));
            } else {
              client.println(F("text"));
              Serial.println(F("text"));
            }
            client.println();

            int16_t c;
            while ((c = file.read()) > 0) {
                // uncomment the serial to debug (slow!)
                Serial.print((char)c);
                client.print((char)c);
            }
            file.close();
          }
        } else {
          // everything else is a 404
          client.println(F("HTTP/1.1 404 Not Found"));
          client.println(F("Content-Type: text/html"));
          client.println();
          client.println(F("<h2>File Not Found!</h2>"));
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    client.stop();
  }
}

void ButtonForm(EthernetClient client, char* name, char* value) {
  client.print("<form method=get>");
//  client.print(F("<input type='hidden' name='")); client.print(name);     client.print(F("' value='")); client.print(value);  client.print(F("'>"));
  client.print(F("<input type='submit' name='")); client.print(name); client.print(F("' value='")); client.print(value);  client.print(F("'>"));
  client.println(F("</form>"));
}
Шифровать Ардуина не шифрует, но шифрованное передает.

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Пн окт 31, 2022 17:30:28

Ariadna-on-Line писал(а):Шифровать Ардуина не шифрует, но шифрованное передает.

кто шифрованное передаёт ?)))

ещё раз... подробно))

1-Ардуины у меня нет... поэтому открываем простой плеер на ПК...
плеер.jpg
(25.8 KiB) Скачиваний: 53

2-берём из скетча Ардуины IP адрес и номер порта...
IP.jpg
(66.93 KiB) Скачиваний: 45

3-закидываем IP адрес и номер порта в плеер на ПК... плеер подключается к серверу...
плеер_205_164_62_15_10032.jpg
(193 KiB) Скачиваний: 47

4-при подключении к серверу плеер передаёт обычный GET запрос...

GET / HTTP/1.0
Accept: */*
User-Agent: WINAMP
Icy-MetaData:1
Host: 205.164.62.15:10032
GET запрос.jpg
(170.96 KiB) Скачиваний: 48

5-сервер передаёт плееру обычный HTTP ответ...

HTTP/1.0 200 OK
icy-br: 192
icy-pub: 1
icy-description: 1.FM - Radio Gaia
icy-url: http://1.fm
Instance-id: ab50168940339c8583715106639d847f
Cache-Control: no-cache
Server: AIS Streaming Server 8.6.5
icy-genre: Chill
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint: 8192
Pragma: no-cache
icy-name: 1.FM - Radio Gaia
Connection: close
Content-Type: audio/mpeg
HTTP ответ.jpg
(165.5 KiB) Скачиваний: 47


Добавлено after 6 minutes 49 seconds:
Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприемник
6-и сразу же сервер передаёт плееру MP3 поток...

ff fb b2 64 e7 88 c5 ce 68 d3 53 6f 64 50 77 ca...
MP3 поток.jpg
(181.83 KiB) Скачиваний: 62

играет музыка))
:music:

7-подробней...
вначале идёт заголовок (ff)... тип файла(fb)... битрейт... и т.д.
ff fb b2 64 e7 88 c5 ce 68 d3 53 6f 64 50 77 ca...
описание.jpg
(84.05 KiB) Скачиваний: 45

потом сам MP3 поток...

Всё ! )))

Никакого шифрования и помине нет ! Никаких шифрованных данных нет ! Всё передаётся по Сети в открытом виде ! ))
:tea:

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вт ноя 01, 2022 00:16:47

Блин. Прошу прощения - описАлся )))))) Хотел написАть что Ардуина передает уже сжатый (MP3) поток, а не сжимает его на лету. Вместо "не сжимает" ляпнул - "не шифрует". Вот что значит вовремя надо спать ложиться.

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Сб дек 17, 2022 04:33:52

Ну как, есть результаты по проекту? :)
(у меня - работает, за основу взял https://wifiradio.su/)

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Пн дек 19, 2022 18:38:44

Извините, я достаточно тупой, особенно в области интернета. Потому не понял как этот приемник получает сигнал. Роутер сам способен поддерживать сотовую сеть ? Или способен работать с USB 3G/LTE модемом ? А то у меня как раз есть подходящий роутер Asus с гнездом для 3G/LTE свистка. Вы смогли сделать такое ? С уважением.

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вт дек 20, 2022 18:30:38

К роутеру кой-какие специфические требования, всё же, предъявляются, например, USB-портов потребуется минимум два, нужен некоторый объём свободной памяти, чтоб встала программа... Но, ничего непреодолимого, как выяснилось... :) (правда, дней пять на настройку "методом тыка" ушло... Кратко: сначала надо поменять прошивку на openwrt с веб интерфейсом LuCI, настроить связь с Интернетом, потом уже настраивать согласно рекомендаций статьи, сделав поправку на то, что подключение будет не по Wi-Fi, а через модем...)

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Ср дек 21, 2022 13:46:57

Ладно. Когда соберете это всё в удобоносимый на природе девайс - буду рад поглядеть.
Лично я склоняюсь к идее использовать USB HOST модуль с Али, куда втыкать 3G/LTE свисток, а модуль к Ардуине. По сути это тот же USB-RS232 конвертор, и стОит копейки. С уважением.
ПС. Блин, - когда-то покупал свистки за копейки, а щас они как смартфоны. С чего бы ???

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Пт дек 23, 2022 05:43:51

Ну, "свисток" нужен в любом случае, а вот "ардуина" будет лишней... :)
...По поводу "поглядеть" - так внешне роутер не меняется! Просто в USB-порты включаются самая обычная звуковая карта и, в Вашем случае, "3G/LTE свисток". Все остальные изменения - только программные, соответственно - обратимые... :)

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вс янв 08, 2023 23:55:08

Роутер с двумя USB портами в продаже не видел ни разу. Что за модель ?

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вт янв 10, 2023 06:28:29

У меня - ростелекомовский Сагем, но, вообще-то, можно пробовать и любой другой - существует такая вещь, как разветвитель USB-портов... (в свободный порт можно будет ещё и флешку подключить, для увеличения внутренней памяти...) Т.е., с "железом" проблем не так много, вот с программной частью, скорее всего, повозиться придётся... Роутеры ведь все чуть-чуть отличаются, поэтому под каждую модель приходится подстраиваться... Может оказаться маловато кнопок для управления, например - тогда выручает звуковая карта с собственными кнопками... :)

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Вт янв 10, 2023 07:06:58

Может будет интересно в плане приемника: https://market.yandex.ru/product--wi-fi ... ir=2&cpa=1 компактный роутер с аккумулятором, в оригинале USB модемы вроде не поддерживает, но можно залить прошивку от asus или еще от какого то именитого роутера, подробнее на 4pda есть, можно оторвать аккумулятор и останется бутерброд из двух плат размером с два пальца. Я их как wi-fi - wi-fi мост использую так что про инет с usb ничего не скажу, только читал об этом.

Re: Хочу сделать Сотовый (не Вай-Фай !!!) интернет-радиоприе

Ср янв 11, 2023 15:49:09

В 2010-ых у меня вообще проводного нета не было, тк городские провайдеры передрались и порушили инфраструктуру. Но к счастью появились 3G свистки и МТС с очень недорогим тарифом. На свистковом 3G, LTE комфортно сидел больше 10 лет. Именно поэтому я энтузазист беспроводки. Недавно у меня тиснули рюкзак со свистками. Зато дома появился относительно недорогой кабель от Билайна. Сунулся подкупить свистков, поглядев на их теперешние цены - сам присвистнул. Вроде бы с прогрессом все должно дешеветь - но наша страна - исключение.
Ответить