По вашему запросу ничего не найдено :(
Убедитесь, что запрос написан правильно, или посмотрите другие наши статьи:
img
Универсальный уникальный идентификатор (UUID - Universally Unique Identifier) – это форма идентификатора, которую можно с уверенностью признать уникальной для большинства практических целей. Даже если два UUID были сгенерированы в двух различных средах двумя сторонами, они имеют ничтожные шансы на то, чтобы оказаться идентичными. Именно поэтому UUID считаются универсально уникальными. В этой статье мы с вами рассмотрим характеристики UUID, то, как работает их уникальность, и сценарии, для которых они могут упростить процесс идентификации ресурсов. Несмотря на то, что мы будем рассматривать UUID с точки зрения программного обеспечения, которое взаимодействует с записями базы данных, их также можно применять и в других ситуациях, где требуется децентрализованная генерация уникальных идентификаторов.  Что такое на самом деле универсальный уникальный идентификатор (UUID)? UUID – это просто значение, которое с уверенностью можно рассматривать как уникальное. Вероятность обнаружения двух одинаковых UUID настолько мала, что ее можно просто игнорировать. Вы можете встретить и другие термины для UUID, например, GUID (Globally Unique Identifier, - глобальный уникальный идентификатор) (такой вариант предпочитает Microsoft), однако смысл и свойства остаются теми же.  Истинный UUID – это уникальный идентификатор, который был сгенерирован и представлен в стандартизированном формате. Допустимые UUID определены в спецификации RFC 4122. Она описывает алгоритмы, которые можно использовать для генерации UUID, которые бы сохраняли свою уникальность в различных реализациях без участия основной выдающей стороны.  В RFC есть пять различных алгоритмов. У каждого из этих алгоритмов есть свой собственный механизм генерации значений. Ниже приведено краткое описание доступных «версий»: Версия 1 – Time-Based – объединяет метку времени, тактовую последовательность и значение, которое является характерным для генерирующего устройства (как правило, это MAC-адрес); таким образом создается выходное значение, которое является уникальным для этого хоста на определенный момент времени. Версия 2 – DCE Security – эта версия была создана как модификация Версии 1, которую можно использовать в среде распределенных вычислений (DCE - Distributed Computing Environment). Применяется не так часто.  Версия 3 – Name-Based (MD5) – MD5 хеширует «пространство имен» и «имя» для того, чтобы создать значение, которое будет уникальным для этого имени в пределах пространства имен. Попытка создать другой UUID с тем же пространством имен и тем же именем приведет к тому, что вы получите идентичный результат. Так что, этот метод дает воспроизводимые результаты.  Версия 4 – Random – большинство современных систем выбирают именно эту версию, поскольку здесь для получения выходного значения используется источник случайных и псевдослучайных чисел. Вероятность того, что будут созданы два одинаковых UUID, ничтожна мала.   Версия 5 – Name-Based (SHA-1) – эта версия в какой-то степени похожа на Версию 3, но здесь для хеширования пространства имен и имени используется более криптостойкий алгоритм SHA-1.  Хоть в RFC алгоритмы и обозначены как «версии», это ни в коем случае не значит, что всегда нужно использовать Версию 5, потому что она вроде бы самая новая. Выбор версии зависит от вашего варианта использования; зачастую выбирается Версия 4 из-за случайного характера генерации значений. Именно это делает ее идеальным вариантом для простых сценариев из разряда «дайте мне новый идентификатор».  Алгоритмы генерации на выходе дают 128-битное целое число без знака. Но при этом UUID чаще всего рассматривают как шестнадцатеричные строки. Также их можно хранить в виде двоичной последовательности из 16 символов. Ниже приведен пример UUID: 16763be4-6022-406e-a950-fcd5018633ca Значение записано с помощью пяти групп буквенно-числовых символов, разделенных дефисом. Последние не являются обязательными составляющими строки; их наличие связано с историческими тонкостями спецификации UUID. А еще они значительно облегчают зрительное восприятие идентификатора.  Варианты использования UUID В основном UUID используют для децентрализованного создания уникальных идентификаторов. Вы можете создать UUID где угодно и с уверенностью сказать, то он уникальный, независимо от того, был он создан на вашем сервере, в клиентском приложении или в вашей базе данных.  UUID упрощают определение и обеспечение идентичности объекта в изолированных средах. Согласно сложившейся практике, большинство приложений в качестве первичного ключа используют целочисленное поле с автоинкрементом. В таком случае, когда вы создаете новый объект, то вы не узнаете его идентификатор до тех пор, пока не добавите его в базу данных. С помощью UUID вы можете определить идентификатор в вашем приложении намного раньше.  Ниже приведен демонстрационный пример, написанный на PHP, который покажет разницу. Для начала давайте посмотрим на целочисленную систему: class BlogPost {    public function __construct(        public readonly ?int $Id,        public readonly string $Headline,        public readonly ?AuthorCollection $Authors=null) {} } #[POST("/posts")] function createBlogPost(HttpRequest $Request) : void {    $headline = $Request -> getField("Headline");    $blogPost = new BlogPost(null, $headline); } Мы должны инициализировать свойство  $Id как  null , поскольку мы не будем знать его фактический идентификатор до тех пор, пока не добавим его в базу данных. Это не самый идеальный вариант –  $Id не должен обнуляться, из-за этого экземпляры  BlogPost находятся в незавершенном состоянии.  Перейдем к UUID; это решит проблему: class BlogPost {    public function __construct(        public readonly string $Uuid,        public readonly string $Headline,        public readonly ?AuthorCollection $Authors=null) {} } #[POST("/posts")] function createBlogPost(HttpRequest $Request) : void {    $headline = $Request -> getField("Headline");    $blogPost = new BlogPost("16763be4-...", $headline); } Идентификаторы публикаций теперь можно создавать прямо в приложении, не думая о том, что они могут повториться. Это гарантирует, что экземпляры объекта всегда находятся в действительном состоянии и что ну нужно присваивать ID нулевое значение. Также эта модель упрощает обработку транзакционной логики; дочерние записи, которым нужна ссылка на родителя (например, взаимосвязи автора ( Author ) нашей публикации), могут быть добавлены немедленно, и не нужно обращаться к базе данных для того, чтобы получить идентификатор родителя.  В перспективе большую часть логики данного приложения-блога можно будет переместить на клиентскую сторону. Возможно, внешний интерфейс сможет поддерживать полностью автономное создание черновиков, по сути создавая экземпляры  BlogPost , которые будут временно сохраняться на устройстве пользователя. Теперь клиент может создавать UUID для публикации и, если ему нужно будет восстановить подключение к сети, передавать его на сервер. Если в обозримом будущем клиент получит копию черновика с сервера, то он сможет сравнить ее с любым сохранившимся локальным состоянием, так как он уже будет знать UUID.  С помощью UUID можно комбинировать данные из различных источников. Объединение таблиц базы данных и кэшей, которые используют целочисленные первичные ключи, может оказаться довольно трудоемким процессом, и, плюс ко всему, в процессе могут возникать ошибки. UUID обеспечивает уникальность идентификатора не только внутри таблиц, но и на уровне всего пространства. Это делает их более предпочтительным вариантом для дублируемых структур и данных, которые часто необходимо перемещать из одной системы хранения в другую. Нюансы, возникающие при встрече UUID с базами данных Преимущества UUID довольно привлекательны. Однако есть несколько подводных камней, о которых следует помнить при использовании UUID в реальных системах. Один из значительных факторов в пользу целочисленных идентификаторов – их легко масштабировать и оптимизировать. Механизмы управления базами данных могут с легкостью индексировать, сортировать и фильтровать список чисел, которые идут одно за другим. А вот про UUID такого сказать нельзя. Прежде всего, UUID в четыре раза больше, чем целое число (36 против 4 байтов); для больших наборов данных этот факт уже может быть существенным моментом. Такие значения намного сложнее сортировать и индексировать, особенно если речь идет о случайных UUID, которые являются самыми популярными. Их случайный характер говорит о том, что они не имеют естественного порядка. Если вы используете UUID в качестве первичного ключа, то это может навредить производительности при индексировании. Все эти проблемы могут усугубляться в хорошо нормализованной базе данных, которая активно использует внешние ключи. В таком случае у вас может оказаться большое количество реляционных таблиц, каждая из которых хранит ссылки на ваши 36-байтные UUID. В конечном счете, дополнительная память, которая необходима для выполнения операций объединения и сортировки, может негативно сказаться на производительность вашей системы.   У вас есть возможность немного сгладить нежелательные последствия, сохранив свои UUID в виде двоичных данных. Это значит, что вместо столбца  VARCHAR(36) у вас будет столбец  BINARY(16) . Некоторые базы данные, например, PostgreSQL, имеют встроенный тип данных  UUID ; другие, например, MySQL, имеют специальные функции, которые преобразовывают строку UUID в двоичную форму и наоборот. Такой подход, конечно, более эффективный, но не забывайте, что вам по-прежнему придется использовать дополнительные ресурсы для хранения и выборки данных.  Эффективной может оказаться стратегия, когда вы в качестве первичных ключей оставляете целые числа, но при этом добавляете дополнительное поле UUID для того, чтобы ваше приложение могло на него ссылаться. Реляционные таблицы ссылок могут использовать идентификаторы для повышения производительности, пока ваш код извлекает и вставляет объекты верхнего уровня с UUID. Здесь все зависит от вашей системы, ее масштаба и ваших приоритетов: если вам нужна децентрализованная генерация идентификаторов и простейшее слияние данных, то лучший вариант – это UUID, но вам следует помнить и об обратной стороне медали. Заключение UUID – это уникальные значения, которые можно использовать для децентрализованной генерации идентификаторов. Совпадение идентификаторов возможно, но вероятность такого события настолько мала, что ее можно не учитывать. Если бы вы генерировали один миллиард UUID в секунду в течении 100 лет, то вероятность обнаружить дубликат составила бы около 50% при условии наличия достаточной энтропии.  У вас есть возможность использовать UUID для установления идентичности независимо от вашей базы данных до того, как вы добавите объект в базу данных. Такой подход упрощает код прикладного уровня и не допускает того, что объекты в вашей системе будут идентифицированы неправильно. UUID также содействуют репликации данных, гарантируя уникальность вне зависимости от хранилища данных, устройства или среды, чего нельзя сказать о целочисленных ключах, которые действуют на уровне таблиц.  Несмотря на то, что UUID широко используются при разработке программного обеспечения, они не являются идеальным решением. Новички часто зацикливаются на возможности обнаружения совпадений, но это не должно быть вашим главным аргументом, если только ваша система не настолько чувствительна, что вам просто необходимо гарантировать уникальность идентификаторов.  Более очевидная проблема для большинства разработчиков заключается в хранении и извлечении сгенерированных UUID. Примитивное использование  VARCHAR(36) (или  VARCHAR(32) , если вы удалите дефисы) в долгосрочной перспективе может оказывать негативное влияние на ваше приложение, так как большая часть попыток оптимизировать индексацию базы данных будут неэффективными. Изучите встроенные средства обработки UUID в вашей системе управления базой данных для того, чтобы максимально улучшить производительность вашего программного решения. 
img
Представим себе следующую задачу: необходимо сделать так, чтобы при входящем звонке клиент слышал музыку в трубке и одновременно с этим звонил телефон у секретаря. Допустим, что у нас нет IVR и мы просто хотим заменить скучные гудки на какую-нибудь приятную музыку пока клиенту кто-нибудь не ответит. Сделать это очень просто. Бежим в модуль Ring Group, закидываем туда нужные внутренние номера и в разделе Play Music On Hold и вместо категории Ring, которая и отправляет в трубку звонящего эти самые скучные гудки, ставим туда какую-нибудь приятную музыку, предварительно добавив новую категорию в модуле Music On Hold. Осталось только поставить новую ринг-группу на входящий маршрут и всё готово. Предельно просто. Сценарий №2 Что если мы хотим сообщить звонящему какую-либо информацию прежде чем он услышит музыку (пойдет вызов на секретаря)? Например, поприветствовать, сообщить имя своей компании и поблагодарить за звонок. Для этого всё в том же модуле Ring Group нужно поставить предварительно записанное сообщение в поле Announcement. Теперь, позвонив в нашу компанию, клиент услышит приветствие, а затем приятную музыку на ожидании, пока ему не ответит секретарь. Нужно отметить, что телефон у секретаря зазвонит только тогда, когда начнёт играть музыка на ожидании, пока проигрывается приветствие из опции Announcement, телефон секретаря будет молчать. Сценарий №3 Допустим, что речь диктора, записанная в нашем приветствии звучит 7 секунд, а для принятия звонка секретарю требуется в среднем 2 секунды. Мы хотим повысить вероятность того, что как только клиент прослушает приветствие, на его звонок сразу же ответят. Согласитесь, оперативность ответа на звонок создаёт у звонящего положительное впечатление о компании. Таким образом, нам нужно как-то задержать момент, когда у секретаря зазвонит телефон где-то на 5 секунд, в то время как звонящий будет слушать текст нашего приветствия. То есть, идеальный сценарий, которого мы хотим добиться следующий: Клиент позвонил в нашу компанию; Клиент слушает наше приветствие (7 секунд); На 5 секунде приветствия, у секретаря начинает звонить телефон; Через примерно 2 секунды, он принимает звонок и начинает общаться с клиентом; Иными словами, нам нужна некая "буферная зона", в которой будут звучать первые 5 секунд нашего приветствия, а на 2 последних секундах у секретаря звонил телефон. Сразу стоит оговориться, что стандартными средствами модулей Ring Group, Inbound Route и Announcement эту задачу решить нельзя. Но в этой статье мы покажем способ, который поможет вам эффективно управлять задержкой отправки сигнала вызова на телефоны, пока звонящий слушает приветствие. Итак, первая хитрость которой мы воспользуемся – это создание звукового файла, в котором речь приветствия и музыка будут звучать друг за другом. То есть, один звуковой файл – сначала текст приветствия, а затем музыка на ожидании, например, в течении 5 минут. Этот файл нужно добавить в новую категорию в модуле Music On Hold А теперь, к созданию той самой "буферной зоны", в которой будут звучат первые 5 секунд нашего звукового файла. Для этого, в модуле Extension нужно создать виртуальный внутренний номер Virtual Extension. Виртуальный внутренний номер – это номер на нашей IP-АТС, который не требует какой-либо регистрации на конечном устройстве (будь то стационарный телефон или просто софтфон), при его создании, система не запрашивает и не создаёт никакого пароля Secret А теперь самое главное – включаем и редактируем правила Follow Me для нашего виртуального внутреннего номера следующим образом. Здесь самыми важными параметрами являются: Initial Ring Time - время, в течение которого, звонок будет идти на этот номер, прежде чем уйдёт на номера из списка Follow-Me List . Это и есть те самые 5 секунд, на которые нам нужно задержать момент, когда у секретаря зазвонит телефон. Follow-Me List - номер, на который уйдёт звонок после времени, указанном в Initial Ring Time. В нашем примере, 1011 – это номер секретаря. Play Music On Hold - звуковой файл, содержащий приветствие и музыку на удержании. Можно выбрать любую стратегию обзвона типа ringall и её модификации. Теперь этот виртуальный внутренний номер можно повесить на входящий маршрут.
img
Многие слышали, но боялись "пощупать" страшного зверя по имени FreeSwitch (FS). Уверяю Вас, что страшного ничего нет. Правда придется перестроить свои мозги на его понимание. Он сильно отличается от Asterisk. И хотя FS такая же программная АТС как и Asterisk, но задачи у них разные. FS позиционируется как "провайдерская" АТС, а Asterisk офисный вариант. Несмотря на это, я его использую даже, как говорится, "для дома, для семьи", то есть дома на одноплатнике Orange PI Plus 2E. Так как на нем стоит Ubuntu 16, то описывать установку я буду для Ubuntu из исходников. Если кому-то нужно попроще, то может установить на Debian (разработчики именно его рекомендуют. Как поставить из пакетов можно почитать здесь https://freeswitch.org/confluence/display/FREESWITCH/Linux А для самых искушенных даже на Windows :) https://freeswitch.org/confluence/display/FREESWITCH/Windows Сначала необходимо выполнить обновление системы: apt-get update apt-get upgrade Установим зависимости: apt-get install autoconf automake devscripts gawk g++ git-core libjpeg-dev libncurses5-dev libtool make python-dev gawk pkg-config libtiff5-dev libperl-dev libgdbm-dev libdb-dev gettext libssl-dev libcurl4-openssl-dev libpcre3-dev libspeex-dev libspeexdsp-dev libsqlite3-dev libedit-dev libldns-dev libpq-dev libtool-bin libopus-dev libshout3-dev libmpg123-dev libmp3lame-dev libsndfile-dev libavresample-dev libswscale-dev libpng-dev libpng++-dev mpg123 После этого перезагружаемся: reboot Создаем папку и клонируем гит: cd /usr/src git clone -b v1.6 https://freeswitch.org/stash/scm/fs/freeswitch.git cd /usr/src/freeswitch ./bootstrap.sh –j Подключаем необходимые модули: mcedit modules.conf + mod_rtmp + mod_directory + mod_callcenter + mod_dingaling + mod_shout + mod_cidlookup + mod_curl + mod_xml_curl Мне нужно было использовать zrtp и хранить данные в базе PostgreSQL (кстати, разработчики считают MySQL недобазой :)) Собираем с ключами: ./configure --enable-zrtp --enable-core-pgsql-support make make install Если при сборке FS ругается на openssl (switch_core_cert.lo) или что то подобное, то нужно проверить версию. Под 1.1.0 не устанавливается. Нужно ставить 1.0.2 Устанавливаем звуковые файлы: 8 kHz Standard Audio make sounds-install make moh-install 16 kHz High Definition Audio make hd-moh-install make hd-sounds-install 32 kHz Ultra High Definition Audio make uhd-moh-install make uhd-sounds-install 48 kHz CD Quality Audio make cd-sounds-install make cd-moh-install Установим русские звуковые файлы: make sounds-ru-install make cd-sounds-ru-install make uhd-sounds-ru-install make hd-sounds-ru-install Установим права и владельцев: adduser --disabled-password --quiet --system --home /usr/local/freeswitch --gecos "FreeSWITCH Voice Platform" --ingroup daemon freeswitch chown -R freeswitch:daemon /usr/local/freeswitch/ chmod -R o-rwx /usr/local/freeswitch/ Создадим init скрипт для запуска /etc/init.d/freeswitch: #!/bin/bash ### BEGIN INIT INFO # Provides: freeswitch # Required-Start: $local_fs $remote_fs # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Description: Freeswitch debian init script. # Author: Matthew Williams # ### END INIT INFO # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin DESC="Freeswitch" NAME=freeswitch DAEMON=/usr/local/freeswitch/bin/$NAME DAEMON_ARGS="-nc" PIDFILE=/usr/local/freeswitch/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME FS_USER=freeswitch FS_GROUP=daemon # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions # # Function that sets ulimit values for the daemon # do_setlimits() { ulimit -c unlimited ulimit -d unlimited ulimit -f unlimited ulimit -i unlimited ulimit -n 999999 ulimit -q unlimited ulimit -u unlimited ulimit -v unlimited ulimit -x unlimited ulimit -s 240 ulimit -l unlimited return 0 } # # Function that starts the daemon/service # do_start() { # Set user to run as if [ $FS_USER ] ; then DAEMON_ARGS="`echo $DAEMON_ARGS` -u $FS_USER" fi # Set group to run as if [ $FS_GROUP ] ; then DAEMON_ARGS="`echo $DAEMON_ARGS` -g $FS_GROUP" fi # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null -- || return 1 do_setlimits start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --background -- $DAEMON_ARGS || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac exit 0 Установим ссылку на CLI cd /usr/local/bin/ ln -s /usr/local/freeswitch/bin/fs_cli fs_cli Проверим всё ли запускается: cd /usr/local/freeswitch/bin ./freeswitch freeswitch@s02d> sofia status (или просто нажимаем F5) freeswitch@s02d> list_users Если нет ошибок, и высветились профили и пользователи, то можно отключаться: freeswitch@s02d> shutdown Меняем стандартный пароль для всех пользователей (указав свой): mcedit /usr/local/freeswitch/conf/vars.xml <X-PRE-PROCESS cmd="set" data="default_password=lkhd456hkhggl2"/> Включаем русский язык, если нужно: mcedit /usr/local/freeswitch/conf/vars.xml <X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/ru/RU/elena"/> <X-PRE-PROCESS cmd="set" data="default_language=ru"/> После правки применяем изменения: fs_cli -x "reloadxml" Устанавливаем необходимые кодеки: mcedit /usr/local/freeswitch/conf/vars.xml <X-PRE-PROCESS cmd="set" data="global_codec_prefs=OPUS,PCMU,PCMA,VP8"/> <X-PRE-PROCESS cmd="set" data="outbound_codec_prefs=OPUS,PCMU,PCMA,VP8"/> Ну и в конце стартуем FS: service freeswitch start Для подключения к FS используем следующую команду: fs_cli -rRS Вот и всё. Мы установили и запустили FreeSwitch. О том, как настраивать пользователей, гейты, диалплан читайте в следующих статьях.
ВЕСЕННИЕ СКИДКИ
40%
50%
60%
До конца акции: 30 дней 24 : 59 : 59