Серебряное наследие
Акустические системы Legacy Audio Focus SE Цена – 1 215 000 руб.
В ассортименте всех компаний, производящих акустические системы и электронные компоненты, есть позиции, благодаря которым обеспечивается основной объем продаж и от которых зависит благосостояние фирмы. Именно такой моделью являются для иллинойсской Legacy Audio напольные колонки Focus, пару лет назад пережившие очередное обновление.
В свое время оригинальные Focus стали для американской компании Legacy настоящим прорывом. Именно они помогли ей превратиться в одного из самых авторитетных производителей акустических систем в США, ведь АС такого размера, способные отрабатывать низкочастотный диапазон со столь высоким качеством, обычно бывают вдвое дороже. Поэтому неудивительно, что глава компании Билл Дадлстон, лично разрабатывающий все выпускаемые фирмой колонки, с особой тщательностью подошел к созданию очередной версии легендарной модели.
Литеры SE в наименовании означают Silver Edition, то есть «серебряное издание». Поводом дать такое название, очевидно, послужило использование во внутренней проводке кабеля Kimber Cable с серебряными жилами, однако изменений в конструкцию АС внесено гораздо больше.
Первое и главное изменение — это новый корпус: по внешнему виду и дизайну Focus SE существенно отличается от модели предыдущего поколения. По словам самого разработчика, основной задачей стало устранение параллельных поверхностей как внутри, так снаружи акустического оформления. Кроме того, были установлены дополнительные стяжки, повышающие жесткость конструкции. Нелишняя мера, учитывая, сколько энергии отдают басовые динамики.
Литеры SE в наименовании означают Silver Edition, то есть «серебряное издание». Поводом дать такое название, очевидно, послужило использование во внутренней проводке кабеля Kimber Cable с серебряными жилами, однако изменений в конструкцию АС внесено гораздо больше. Что касается облика, то в этом отношении был сделан большой шаг вперед по сравнению с прежними версиями с их ретродизайном. Отделка лакированных граней, да и качество изготовления в целом, просто безупречны. Достаточно сказать, что покрытие Black Pearl образуется в результате нанесения четырнадцати слоев лака и выдержки в течение четырнадцати недель перед окончательно полировкой. Каждая колонка весит больше 60 кг и устанавливается на массивные точеные бронзовые ножки. Сдвоенный порт фазоинвертора по традиции выведен назад, там же находятся мощные клеммы, допускающие подключение второй пары усилителей для пассивного биампинга.
Что же касается использованных здесь динамиков, то главное отличие заключается в существенно более строгом отборе пар по АЧХ. Если раньше они подбирались с допуском 1 дБ, то для Legacy Focus SE допустимая погрешность составляет уже не более 0,25 дБ. Опыт подсказывает, что процент отбраковки в таком случае чрезвычайно высок. При этом снятая с каждого динамика АЧХ сохраняется в базе данных компании на тот случай, если какой-либо из них в процессе эксплуатации выйдет из строя и потребуется его замена.
Низкочастотный диапазон озвучивается уже ставшими привычными для Legacy 12-дюймовыми вуферами. Все они оснащены мощными неодимовыми магнитами и не самыми легкими алюминиевыми диффузорами. Подвесы головок — резиновые, с большой длиной хода; корзины, разумеется, литые. Басовая секция работает вплоть до 120 Гц и передает эстафету сдвоенным мидбасовым динамикам, отвечающим за участок, ограниченный 2800 Гц. 7-дюймовые драйверы имеют мощнейшие ферритовые магниты и диффузоры из материала Silver Graphite, представляющего собой плетеный композит из углеродных волокон с включением серебра, на подложке из пористого материала Rohacell, гарантирующего отличные показатели внутреннего демпфирования. За средние и высокие частоты отвечает сдвоенный ленточный модуль AMT (Air Motion Transformer). На участке до 8000 Гц работает «лента» длиной 4 дюйма, выше в действие вступает аналогичный дюймовый супертвитер. Хотя Legacy Audio не раскрывает имя изготовителя ВЧ-излучателей для Focus SE, все указывает на то, что им является немецкая компания Mundorf, которая широко известна своими конденсаторами, катушками и резисторами аудиофильского качества, используемыми подавляющим большинством производителей АС класса High End. Чтобы добиться от Legacy Focus SE максимального результата, необходимо позаботиться о правильном их окружении. К счастью, в нашей тестовой системе работала связка предварительного усилителя Krell Illusion с моноблоками Krell Solo 375, которая в состоянии взять под абсолютный контроль четыре басовых динамика с алюминиевыми диффузорами на резиновых подвесах. Поскольку, на наш взгляд, данное сочетание электроники близко к идеальному для испытуемых колонок, их выступление можно оценивать без каких-либо поблажек.
Скажем несколько слов об источнике сигнала. Диски для нас крутил отличный медиацентр Electrocompaniet ECM-2, способный работать также в качестве предварительного усилителя. Он может брать музыку не только с внешнего NAS-сервера, но также со встроенного жесткого диска и даже с подключаемых USB-накопителей. За организацию и управление медиатекой отвечало фирменное приложение Electrocompaniet, доступное для планшетов и телефонов на iOS и Android. Командовать воспроизведением с его помощью определенно удобнее, чем посредством комплектного пульта ДУ. Само собой, медиацентр работает с файлами разрешением до 24 бит / 192 кГц, а также с DSD-потоками. Коммутация осуществлялась хорошо известными и проверенными в деле кабелями Analysis Plus.
Прежде чем переходить к впечатлениям от прослушивания, необходимо подробно остановиться на размещении колонок в комнате. Высокие черные обелиски с двойными басовиками требуют не только хорошего и мускулистого усилителя для демонстрации своих способностей, но и тщательной продуманной установки в помещении. Особое внимание нужно уделить расположению слушателя. Совершенно необходимо, чтобы голова его находилась на уровне средне- высокочастотного звена, в противном случае частотный баланс будет нарушен. Также следует учесть, что передняя панель колонок немного наклонена назад, поэтому лучше слушать их все-таки в дальнем поле. Это тоже одна из мер, дающих возможность в полной мере оценить басовый напор Legacy. По счастью, наша тестовая комната позволила соблюсти все нужные условия. Наличие в кроссовере выравнивающего контура на низких частотах может оказаться полезным, когда необходимо избавиться от назойливых комнатных мод в небольших помещениях, однако практика показала, что лучше все же потратить время и силы на инсталляцию АС, не прибегая к его активации.
В свое время, с подачи некоторых чересчур ретивых британских аудиожурналистов, в обиход вошло такое понятие, как «американский звук». Это клеймо ставилось на все мощные полнодиапазонные акустические системы, от JBL до Dunlavy (включая сюда, разумеется, и Legacy), которые, в отличие от многих своих европейских конкурентов, способны воспроизвести весь диапазон мужского вокала, не наделяя солистов талантами Фаринелли. Так вот: необходимо удалить из памяти, забыть навсегда весь тот вздор, что был понаписан про пресловутый американский звук. Не существует никакого американского, английского, немецкого или итальянского звука. Есть просто хорошие или плохие колонки. И Legacy Focus SE — очень хорошие колонки. Более того: просто замечательные!
Известно, что весьма непросто подружить ленточные излучатели с динамическими головками таким образом, чтобы первые не доминировали над вторыми. Но Билл Дадлстон справился с задачей блестяще. Использование ленточников и серебряных кабелей в высокочастотной цепи если и угадывается, то лишь по великолепной проработке мельчайших деталей и вкусному и длительному затуханию — и что особенно приятно, при полном отсутствии какой-либо окраски.
Максимальная натуральность звучания и комфорт — вот что всегда отличало модель Focus и что является одним из достоинств новой ее версии. Уютные домашние тапочки — так можно было охарактеризовать звуковой почерк первых Focus. Теперь же, развивая эту ассоциацию, впору говорить о стильных и оригинально расшитых кожаных туфлях ручной работы. Звук стал куда более собранным и динамичным, с превосходной атакой во всем диапазоне, но одновременно он не утратил комфортность, столь ценимую поклонниками Focus.
Переходя к более подробному описанию звучания АС, отметим, что сцена прорисована очень неплохо, хотя для ее проявления необходимо найти правильное расположение слушателя и колонок в комнате. Тембры инструментов абсолютно натуральны, солирующая труба всегда сохраняет живость и присущую ее тембру шероховатость, никогда не срывается на визг. Столь же естественно передаются остальные духовые инструменты.
Максимальная натуральность звучания и комфорт — вот что всегда отличало модель Focus и что является одним из достоинств новой ее версии. Уютные домашние тапочки — так можно было охарактеризовать звуковой почерк первых Focus. Теперь же, развивая эту ассоциацию, впору говорить о стильных и оригинально расшитых кожаных туфлях ручной работы.
Что сказать о басе? Он великолепен, как и всегда у Legacy. Если электронные компоненты соответствуют уровню колонок, то пользователь услышит все преимущества, предоставляемые мощной низкочастотной секцией. Когда того требует фонограмма, Focus SE взрываются просто-таки как склад с динамитом, а когда это не нужно, мягко мурлычут партию контрабаса на заднем плане. Они не обманут ожиданий ни любителей рока и джаза, ни поклонников сложных симфонических произведений. По счастью, модель отрабатывает на все сто краски большого симфонического оркестра, обрушивая на благодарного слушателя всю его мощь. Колонки благодарно отзываются на качественные записи, но вместе с тем не лучшим образом записанные диски не заставят вас выбежать из комнаты в ужасе. Вся ваша коллекция будет звучать в диапазоне от «хорошо» до «сногсшибательно».
Полный список
В этом уроке:
— используем Audio Focus
Наверняка вы замечали, что при прослушивании музыки, если срабатывает уведомление, то на время звучания уведомления звук музыки или прерывается или становится тише. Это можно реализовать с помощью аудио-фокуса.
Попробую сначала объяснить схему движения фокуса на словах. Если рассматривать пример музыки и уведомления, то пусть музыку играет некое приложение_1, а уведомления выдает некое приложение_2. Приложение_1, когда начинает воспроизведение, запрашивает аудио-фокус, получает его и играет музыку. Далее приходит смс или письмо, и приложение_2 хочет воспроизвести звук уведомления. Оно также запрашивает аудио-фокус и получает его. Но при этом система видит, что фокус сейчас у приложения_1. Система сообщает приложению_1, что фокус оно пока что потеряло. Звук уведомления воспроизводится, приложение_2 отдает фокус, а приложению_1 сообщают, что фокус снова его. Когда приложение_1 заканчивает играть музыку, оно отдает фокус. Т.е. приложение должно не только запрашивать фокус при необходимости, но и явно отдавать его, когда он более не нужен. Для этого есть специальные методы, мы их рассмотрим дальше.
Тут еще важно понимать, что эти сообщения от системы к приложениям о том, что фокус потерян/восстановлен являются просто уведомительными. И разработчик приложения сам решает, как он будет это обрабатывать: проигнорит, убавит звук или приостановит воспроизведение. Например, я протестировал два плеера на своем планшете. На одном включил музыку и свернул его, музыка продолжала играть в фоне. В другом плеере я запустил просмотр фильма. В результате я слышал и фильм и музыку. Аудио-фокус позволяет избежать этого.
Можно провести аналогию с человеком. Допустим, какой-то человек громко говорит. Его просят говорить потише, а еще лучше совсем заткнуться, т.к. он мешает остальным и вообще достал, и все хотят послушать другого человека. Вот это и есть потеря аудио-фокуса первым человеком. Но ведь это вовсе не означает, что этот человек тут же замолчит. Ему просто поступило уведомление, что другой человек хочет говорить. И первый человек поступает так, как считает нужным: либо продолжает громко говорить, либо будет говорить потише, либо замолчит. Это остается на его усмотрение, особенно если он наглый, сильный или быстро бегает )
Напишем приложение, в котором реализуем пример с музыкой и звуком. При нажатии на одну кнопку будем запускать проигрывание музыки, а при нажатии на другую – воспроизводить короткий звук. И привяжем к этой схеме аудио-фокус.
Создадим проект:
Project name: P1281_AudioFocus Build Target: Android 2.3.3 Application name: AudioFocus Package name: ru.startandroid.develop.p1281audiofocus Create Activity: MainActivity
Добавим строки в strings.xml
:
Music Sound G Sound GT Sound GTD
layout-файл main.xml
:
Кнопка Music
будет запускать музыку, а три другие кнопки – звук. Их три, потому что есть три разных типа фокуса, которые может запросить приложение. Мы протестируем все три.
В папку mnt/sdcard/Music/
поместите какой-нить файл с именем
music.mp3
. Например, его можно взять здесь. В папку
res/raw
поместите файл
explosion.mp3
, например отсюда.
MainActivity.java
:
package ru.startandroid.develop.p1281audiofocus; import java.io.IOException; import android.app.Activity; import android.content.Context; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.util.Log; import android.view.View; public class MainActivity extends Activity implements OnCompletionListener { final static String LOG_TAG = «myLogs»; AudioManager audioManager; AFListener afListenerMusic; AFListener afListenerSound; MediaPlayer mpMusic; MediaPlayer mpSound; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); } public void onClickMusic(View view) { mpMusic = new MediaPlayer(); try { mpMusic.setDataSource(«mnt/sdcard/Music/music.mp3»); mpMusic.prepare(); } catch (IOException e) { e.printStackTrace(); } mpMusic.setOnCompletionListener(this); afListenerMusic = new AFListener(mpMusic, «Music»); int requestResult = audioManager.requestAudioFocus(afListenerMusic, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); Log.d(LOG_TAG, «Music request focus, result: » + requestResult); mpMusic.start(); } public void onClickSound(View view) { int durationHint = AudioManager.AUDIOFOCUS_GAIN; switch (view.getId()) { case R.id.btnPlaySoundG: durationHint = AudioManager.AUDIOFOCUS_GAIN; break; case R.id.btnPlaySoundGT: durationHint = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT; break; case R.id.btnPlaySoundGTD: durationHint = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; break; } mpSound = MediaPlayer.create(this, R.raw.explosion); mpSound.setOnCompletionListener(this); afListenerSound = new AFListener(mpSound, «Sound»); int requestResult = audioManager.requestAudioFocus(afListenerSound, AudioManager.STREAM_MUSIC, durationHint); Log.d(LOG_TAG, «Sound request focus, result: » + requestResult); mpSound.start(); } @Override public void onCompletion(MediaPlayer mp) { if (mp == mpMusic) { Log.d(LOG_TAG, «Music: abandon focus»); audioManager.abandonAudioFocus(afListenerMusic); } else if (mp == mpSound) { Log.d(LOG_TAG, «Sound: abandon focus»); audioManager.abandonAudioFocus(afListenerSound); } } @Override protected void onDestroy() { super.onDestroy(); if (mpMusic != NULL) mpMusic.release(); if (mpSound != NULL) mpSound.release(); if (afListenerMusic != NULL) audioManager.abandonAudioFocus(afListenerMusic); if (afListenerSound != NULL) audioManager.abandonAudioFocus(afListenerSound); } class AFListener implements OnAudioFocusChangeListener { String label = «»; MediaPlayer mp; public AFListener(MediaPlayer mp, String label) { this.label = label; this.mp = mp; } @Override public void onAudioFocusChange(int focusChange) { String event = «»; switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: event = «AUDIOFOCUS_LOSS»; break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: event = «AUDIOFOCUS_LOSS_TRANSIENT»; break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: event = «AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK»; break; case AudioManager.AUDIOFOCUS_GAIN: event = «AUDIOFOCUS_GAIN»; break; } Log.d(LOG_TAG, label + » onAudioFocusChange: » + event); } } }
В onCreate
мы просто получаем AudioManager. Именно через него мы будем запрашивать фокус.
onClickMusic
срабатывает при нажатии кнопки Music. Здесь мы создаем MediaPlayer и даем ему путь к файлу с музыкой. Методом setOnCompletionListener устанавливаем Activity, как получателя уведомления о окончании воспроизведения. Далее идет работа с фокусом. afListenerMusic – это слушатель (реализующий интерфейс OnAudioFocusChangeListener), который будет получать сообщения о потере/восстановлении фокуса. Он является экземпляром класса AFListener, который мы рассмотрим чуть дальше.
Фокус запрашивается с помощью метода requestAudioFocus. На вход необходимо передать: — слушателя, который будет получать сообщения о фокусе — тип потока — тип фокуса
Тип фокуса говорит о том, насколько долго приложение собирается воспроизводить свой звук и насколько важно, чтобы другое приложение при этом замолчало. Всего есть три типа фокуса: AUDIOFOCUS_GAIN – приложение дает понять, что оно собирается долго воспроизводить свой звук, и текущее воспроизведение должно приостановиться на это время AUDIOFOCUS_GAIN_TRANSIENT – воспроизведение будет коротким, и текущее воспроизведение должно приостановиться на это время AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK – воспроизведение будет коротким, но текущее воспроизведение может просто на это время убавить звук и продолжать играть
Итак, мы запрашиваем фокус и говорим, что это надолго — AUDIOFOCUS_GAIN. Метод requestAudioFocus возвращает статус: AUDIOFOCUS_REQUEST_FAILED = 0 – фокус не получен AUDIOFOCUS_REQUEST_GRANTED = 1 – фокус получен
После того, как получили фокус, стартуем воспроизведение.
Метод onClickSound
срабатывает при нажатии на любую из трех кнопок Sound. Здесь мы определяем, какая из трех кнопок была нажата. Тем самым мы в переменную durationHint пишем тип аудио-фокуса, который будем запрашивать. Далее создаем MediaPlayer, который будет воспроизводить наш звук взрыва из папки raw. Присваиваем ему слушателя окончания воспроизведения. Запрашиваем фокус с типом, который определили выше. Стартуем воспроизведение.
Метод onCompletion
, срабатывает по окончании воспроизведения. Мы определяем, какой именно MediaPlayer закончил играть и методом abandonAudioFocus сообщаем системе, что больше не претендуем на аудио-фокус. На вход методу передаем того же слушателя, который давали при запросе фокуса.
В onDestroy
освобождаем ресурсы и отпускаем фокус.
Класс AFListener
реализует интерфейс OnAudioFocusChangeListener и является получателем сообщений о потере/восстановлении фокуса. При создании мы даем ему соответствующий MediaPlayer (позже станет понятно зачем) и текст, который нам понадобится для логов.
Метод onAudioFocusChange получает на вход статус фокуса этого приложения. Тут 4 варианта: AUDIOFOCUS_LOSS – фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN. Т.е. нам дают понять, что другое приложение собирается воспроизводить что-то долгое и просит нас пока приостановить наше воспроизведение. AUDIOFOCUS_LOSS_TRANSIENT — фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN_TRANSIENT. Нам дают понять, что другое приложение собирается воспроизводить что-то небольшое и просит нас пока приостановить наше воспроизведение AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK — фокус потерян в результате того, что другое приложение запросило фокус AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK. Нам дают понять, что другое приложение собирается воспроизводить что-то небольшое, и мы можем просто убавить звук, не приостанавливая воспроизведение AUDIOFOCUS_GAIN – другое приложение закончило воспроизведение, звук снова наш
Пока что мы просто будем выводить в лог всю эту информацию, чтобы увидеть схему взаимодействия двух приложений с аудио-фокусом.
Все сохраним и запустим приложение. Жмем Music, воспроизведение музыки началось. В логах видим.
Music request focus, result: 1
Т.е. музыка запросила фокус и получила его (статус = 1).
Жмем Sound G, чтобы воспроизвести звук взрыва и запросить фокус AUDIOFOCUS_GAIN.
Sound request focus, result: 1
Music onAudioFocusChange: AUDIOFOCUS_LOSS
Фокус запрошен и получен взрывом. А музыка получила уведомление о том, что фокус она потеряла (AUDIOFOCUS_LOSS).
Слышим звук взрыва. После того как звук взрыва закончился:
Sound: abandon focus
Music onAudioFocusChange: AUDIOFOCUS_GAIN
Срабатывает метод onCompletion, в котором взрыв отдает фокус (abandon focus). И, следовательно, музыка получает сообщение о том, что фокус снова ее (AUDIOFOCUS_GAIN).
Если дождаться, когда закончится музыка увидим такое сообщение.
Music: abandon focus
Музыка отдала фокус.
Как вы заметили, музыка все это время играла и никуда не делась. То, что она теряла фокус – не означает автоматически, что она остановится. Повторюсь, фокус – это только уведомление. А как приложение отреагирует на это уведомление – решать вам, как разработчику.
Кнопки Sound GT и Sound GTD срабатывают аналогично, я уже не буду их нажимать. Отличие будет в том, что взрыв будет запрашивать фокусы соответственно AUDIOFOCUS_GAIN_TRANSIENT и AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK. А музыка будет получать статусы AUDIOFOCUS_LOSS_TRANSIENT и AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK.
Т.е. мы увидели как одно приложение запрашивает определенный тип фокуса, а другое приложение видит этот тип и должно принимать соответствующие меры. Кстати о мерах. Давайте кроме логов реализуем и эти меры.
Перепишем метод onAudioFocusChange
класса AFListener:
public void onAudioFocusChange(int focusChange) { String event = «»; switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: event = «AUDIOFOCUS_LOSS»; mp.pause(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: event = «AUDIOFOCUS_LOSS_TRANSIENT»; mp.pause(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: event = «AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK»; mp.setVolume(0.5f, 0.5f); break; case AudioManager.AUDIOFOCUS_GAIN: event = «AUDIOFOCUS_GAIN»; if (!mp.isPlaying()) mp.start(); mp.setVolume(1.0f, 1.0f); break; } Log.d(LOG_TAG, label + » onAudioFocusChange: » + event); }
При потерях фокуса AUDIOFOCUS_LOSS и AUDIOFOCUS_LOSS_TRANSIENT ставим паузу. А при AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK – просто уменьшаем громкость. При получении же фокуса (AUDIOFOCUS_GAIN) возобновляем воспроизведение, если оно было приостановлено, и ставим громкость на максимум.
Я выбрал самые простые меры, чтобы не усложнять урок. Но их можно улучшить. Например, при потере фокуса надолго (AUDIOFOCUS_LOSS) можно освобождать ресурсы, и снова создавать MediaPlayer при получении фокуса. Либо можно вообще полностью отдать фокус (abandon), и тогда пользователю надо будет явно вернуться в ваше приложение, чтобы возобновить воспроизведение.
Когда вы запрашиваете фокус, метод requestFocus возвращает вам ответ, получилось захватить фокус или нет. Хелп рекомендует учитывать этот параметр и стартовать воспроизведение только при положительном результате (AUDIOFOCUS_REQUEST_GRANTED). Я, правда, не знаю как тут можно получить отрицательный результат. Если у кого есть соображения на этот счет – пишите на форуме.
На следующем уроке:
— пишем звук с помощью MediaRecorder
Присоединяйтесь к нам в Telegram
:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Обсудить на форуме [7 replies]