Ответы пользователя по тегу JavaScript
  • Как реализовать такой скролл как на thewitcher.com/en/witcher3?

    HoHsi
    @HoHsi
    Предположу, что это на банальном эвенте wheel + throttle/debounce

    const body = document.getElementsByTagName('body')[0];
    body.addEventListener('wheel', _.throttle((e) => {
      const isNext = e.deltaY > 0;
    
      if (isNext) {
        // Следующий слайд
        console.log('->');
      } else {
        // Предыдущий слайд
        console.log('<-');
      }
    }, 1000, {
      trailing: false
    }));
    Ответ написан
    Комментировать
  • {}.toString.call(obj).slice(8, -1) Почему (8,-1)?

    HoHsi
    @HoHsi
    Слайс - метод массивов и строк, т.е. по сути этот метод вырезает часть из массива.

    В данном случае, мы посредствам, допустим ({}).toString.call([]) получим "[object Array]", т.е. строку, которая содержит имя конструктора.

    По спеку, JS выводит строку в следующем формате: "[object <NAME_OF_CONSTRUCTOR>]", и следовательно если вырезать все, кроме 8 до предпоследного символа, мы получим само имя
    Ответ написан
    Комментировать
  • На сколько хорошо использовать NodeBB?

    HoHsi
    @HoHsi
    NodeBB работает на Javascript, что соответственно не делает не какой нагрузки на сервер.

    Делает. Все что работает на сервере, даже grep, делает на него нагрузку. Тут вопрос в том какую нагрузку он делает. Та же нода будет независимо от кол-во пользователей есть 50mb RAM. Но в свою очередь за счет этого будет быстрее отвечать. Это позволит обслужить большее кол-во пользователей, но за счет постоянного проживания в RAM.

    Но я не совсем понимаю как это работает, прогуглил и понял что оно работает на MongoDB и не совсем понял, получается данные с сайта который мы сделаем на NodeBB, такие как имена и пароли пользователей, вопросы, ответы и т.д. хранятся полностью на серверах MongoDB ? И

    Аммм, ну да. Так работают все Web приложения. Они хранят почти все динамические данные в базах. И не важно, SQL это, или NoSQL.

    Если вы подразумеваете, что есть какие-то MongoDB сервера, как сервисы, то нет. Это просто база данных, как Postresql или MySQL. Вам прийдется ее так же поднимать на одной из своих машин, что автоматически значит, что вы храните все "у себя".

    Если же вы подразумеваете, что данные хранятся непосредственно в процессе NodeJS, это от части правильно, но все равно 90% данных будут лежать в базе, те же пользователи, вопросы и т.д.

    И по этому может хоть до миллионов запросов быть? Или как это работает?

    Нет. Вы все так же ограничены RAM, CPU, пропускной способностью, лимитом трафика. Все тоже самое, что и в других Web приложениях, на любых языках и платформах. Никакой магии.
    Ответ написан
    4 комментария
  • Что делает [2], в данном .match?

    HoHsi
    @HoHsi
    [2] вообще не относится к регулярке. Это выбор элемента массива. Так как match в JS (да и во всех реализациях) возвращает массив, то вы просто выбираете 3-ий элемент. Т.е:
    /^\/([a-z]*\/[a-z].*?\/[a-z].*?)-(.*).*/

    Что у вас там лежит известно только вам.
    Но сейчас вы пытаетесь взять второй 3-ий элемент от Null
    Ответ написан
    Комментировать
  • Как подменить результат вызова стандартного node.js модуля в тестах?

    HoHsi
    @HoHsi
    const child_process = {};
    child_process.exec = function () {
      // Все что угодно
    }


    Если CP используется не в тесте, а в самой либе, тогда можно как-нибудь извратиться с передачей child_process как параметра, тогда можно будет подсовывать любые функции вместо нее.
    Ответ написан
  • Переменная не хочет переопределяться. Почему?

    HoHsi
    @HoHsi
    Если хотите использовать асинхронные операции в синхронном стиле, придется прикрутить промисы

    /** Переписываем с промисами */
    function getLoc(options) {
      if (navigator.geolocation ){
        // Запускаем новый промис
        return new Promise((resolve, reject) => {  
          navigator.geolocation.getCurrentPosition((pos) => {
            resolve(pos);
          }, (err) => {
            reject(err);
          }, options);
        });
      } else {
        // Если нет, возвращаем заглушку, или можете сделать "reject"
        return Promise.resolve({
          pos: {
            coords: {
              latitude: 0,
              longitude: 0
            }
          }
        });
      }
    }
    
    getLoc()
    .then((pos) => {
      const {
        latitude: lat,
        longitude: lon
      } = pos.coords;
    
      console.log("Wow");
      console.log("So promissed");
      console.log(lat, lon);
    })
    .catch((err) => {
      // Пользователь отказался давать координаты
      console.log(":(");
      console.error(err);
    });
    Ответ написан
    2 комментария
  • Как вернуть из асинхронных функции результат?

    HoHsi
    @HoHsi
    Во первых вы вызываете асинхронную версию exec, есть ее синхронный собрат: execsync

    Во вторых, тут не обойдется без промисов / коллеков / Async/Await.
    В текущей сборке, я бы рекомендовал использовать промисы, но сам я уже перешел на Async/Await c бабелем.
    function enabledApi(conf) {
      const config = {
        host:     conf.host,
        username: conf.us,
        password: conf.pa
      };
    
      return new Promise((resolve, reject) => {
        exec(config, '/ip service set api disabled=no', (error, response) => {
          const res = error ? 'error' : 'ok';
          console.log(`res is ${res}`);
    
          if (error) {
            reject(error);
          } else {
            resolve(response);
          }
        });
      });
    }
    
    const config = {
      host:'1.1.1.1',
      us:'user',
      pa:'123'
    };
    
    enabledApi(config)
    .then((res) => {
      console.log(`ress again is ${res}`);
    })
    .catch((err) => {
      console.error(`OMG! ${err.toString()}`);
    });


    Или все же с Async, но вам понадобится babel
    function enabledApi(conf) {
      const config = {
        host:     conf.host,
        username: conf.us,
        password: conf.pa
      };
    
      return new Promise((resolve, reject) => {
        exec(config, '/ip service set api disabled=no', (error, response) => {
          const res = error ? 'error' : 'ok';
          console.log(`res is ${res}`);
    
          if (error) {
            reject(error);
          } else {
            resolve(response);
          }
        });
      });
    }
    
    (async () => {
      const config = {
        host:'1.1.1.1',
        us:'user',
        pa:'123'
      };
    
      const res = await enabledApi(config);
    
      console.log(res);
    })()
    .catch((err) => {
      console.error(`OMG! ${err.toString()}`);
    });
    Ответ написан
    Комментировать
  • Почему не видно значения переменной?

    HoHsi
    @HoHsi
    Это называется IIFE. Так как запрос к базе - асинхонный, а for - синхонный, он отрабатывает быстрее, сохраняя внутренее значение i на финальной итерации. Это значит, что вам нужно замкнуть для каждого вызова i, что-бы он стал локальным. Это проблема var переменны, так как имеют область видимости всей функции, а не блока. Это можно решить:
    1 вариант - по старинке:
    for (var i=0, len = vendors.length; i < len ; i++) {
        (function (i) {
            console.log(i);
            connection.query('SELECT * FROM `brends` WHERE `brend_parrent`="'+vendors[і].id_folders+'";', function(err, rows, fields) {
                if (err) throw err;
                console.log(i);
            });
        })(i);
    }


    2 - с использованием ES6 let:
    for (let i=0, len = vendors.length; i < len ; i++) {
        console.log(i);
        connection.query('SELECT * FROM `brends` WHERE `brend_parrent`="'+vendors[і].id_folders+'";', function(err, rows, fields) {
            if (err) throw err;
            console.log(i);
       });
    }
    Ответ написан
    Комментировать
  • Как преобразовать массив полученный от mysql в другой вид?

    HoHsi
    @HoHsi
    connection.query('SELECT user FROM users', function(err, rows, fields) {
      if (err) { throw err; };
      
      const users = rows.map((row) => ""+row.user);
      callback(`Текст: ${JSON.stringify(users)}`);
    });
    Ответ написан
    Комментировать
  • Нужно ли оборачивать синхронную функцию в setTimeout, если нужно вернуть promise?

    HoHsi
    @HoHsi
    Если вы выполняете функцию без сайд-эффекта (это не запрос к базе / API / тому, что может не ответить), то вообще можете вернуть
    return Promise.resolve(data);
    Ответ написан
    Комментировать
  • Лучший способ реализации мультиязычности на Node.js?

    HoHsi
    @HoHsi
    Ответ написан
    Комментировать
  • Как скрыть javascript на сервере?

    HoHsi
    @HoHsi
    Это невозможно. Если скрипт встраивается в сайт, т.е. фронт энд, а не является бэк-энд NodeJS скриптом, его нельзя скрыть.

    Если же упороться, и закрыть доступ к этому файлу, его не получат и пользователи, которые просто перешли на страницу. Это все равно, что заварить дверь от воров, и удивляться, а почему же не заходят обычные покупатели.

    Единственный способом мало-мальски скрыть исходные тексты, это обфускация и минификация.
    Все.

    P.S. Дайте ссылку на пример где так сделано, аж любопытно.
    Ответ написан
    3 комментария
  • Как создать сайт вроде спрашивай.ру?

    HoHsi
    @HoHsi
    Не стоит сразу же замахиваться на большой сервис, начните постепенно. Каждый начинающий программист первым своим проектом грезит сделать убийцу ВК / FB. Скажу сразу, это с первого раза не выйдет. Как не выйдет и с 10. Но! Это не повод, что-бы не развиваться и не учиться. Итак если вы все же решили потрать пару месяцев на обучение, или вы уверены, что пойдет меньше, начните так:

    Шаг первый
    Html. Это язык разметки, на котором написано 100% веба, то есть это необходимая вещь де-факто. Он позволит вам разместить текст на странице, оформить ее.
    В базовой аналогии, это ворд для интернета (кышь Ъ праграммысты, это довольно хорошая аналогия для новичка, продолжим...).

    Это займет +- 1 неделю

    Вам помогут:
    * htmlbook

    Шаг второй
    CSS. Это язык стилизации. Перекрасить текст, увеличить отступы, сделать тень у блоков это к нему. Все крависости в интернете делаются на нем. 99% веба использует для стилизации именно его, так что опять же это стандарт.

    Это займет +- 2 недели

    Вам помогут:
    * Sorax

    Шаг третий
    PHP. Это уже язык программирования (плохой, больной, уродливый, но язык. Да начнется холивар). Он поможет вам понять как это работает, как устроена кухня. Поковыряйте его, обучитесь начальной логике и алгоритмам. Он поможет вам выводить HTML более осмыслено, т.е. вы сможете уже составлять динамические страницы, которые могут подстраиваться под пользователя, добавлять посты, вопросы, картинки и т.д.

    Это займет +- 2 месяца

    Вам помогут:
    * php.net

    Шаг четвертый
    Wordpress. Это почти готовый сайт. В нем уже есть все, что вам нужно. Вы можете писать посты, делать обсуждения и т.д. На его основе вы сможете вылепить что угодно, даже тот самый вопросник. Он написан на PHP, так что он будет дополнять ваши знания. Как только научитись ставить WP, попробуйте написать для него шаблон, потом плагин, и еще и еще. Это закрепит и разовьет ваши предыдущие знания.

    Это займет +- 2 месяца

    Вам помогут:
    * wp-kama

    Шаг пятый
    MySQL. И в частности язык запросов SQL. Это база данных. Они нужны, что-бы хранить информацию вашего сайта в удобном виде. Т.е. по своей сути это таблица экселя, в ней есть поля и их значения. Это так же необходимые знания, так как ваши вопросы из вопросника будух храниться именно там.

    Это займет +- 1 месяц

    Переломный момент
    Наступает переломный, это значит что по истечению полу-года вы должны сесть и подумать, нравится ли вам, что вы делали. Это важно. Так как дальше не будет проще, не будет легче. Начнутся такие вещи как Асинхронность, Брокеры сообщений, ООП, MVC, и другие страшные слова, которые ровно как и предыдущие шаги по-началу будут вас пугать, но потом станут лучшими друзьями.

    Если вам действительно интересно большее, то можете изучить шаги приведенные ниже. Если же вы просто хотите развлечься, то вам вполне хватит перечисленных выше.

    Не спешите так же переходить к шагам ниже, если не уверены в своих силах. Нет ничего плохого, что-бы "посидеть" еще на предыдущих шагах.

    Шаг пятый
    JavaScript. Ура, вы решили, что вы хотите быть программистом, похвально. Этот язык позволит вам сделать ваши страницы более динамичными. Добавить на них анимацию, логику. Этот язык использует 90% веба, так что сомневаться в его значимости нет смысла. Он позволит вам добавить жизнь на ваш сайт.

    Это займет +- 2 месяц

    Вам помогут:
    * Sorax
    * learn.javascript.ru

    Шаг шестой
    Jquery. Это продолжение JS. Это фреймворк (набор готовых функций). Он облегчит вашу работу с JS и позволит делать ее более качественно и быстро.

    Это займет +- 1 месяц

    Шаг седьмой
    Распутье. Вы уже как год программист, отличная работа. Вы уже выросли из яслей и впереди бескрайний океан. И теперь вы должны понять, что вы хотите. Устраивают ли вас сейчас ваши текущие инструменты. Удобные ли они. Не стесняют ли они вас.

    Если вам нравится PHP, он удобен, тогда продолжите изучать именно его, но не стоит бездумно и слепо защищать язык. Если вы чувствуете, что он вас смущает, не противьтесь и просто попробуйте что-то другое. А поверьте этого много.

    Итак развилка:
    Мне нравится PHP, мама я женюсь!
    Ок, тогда вам стоит взглянуть на фреймворки Laravel, Yii 2, вполне хороши. Они довольно мощные и позволят много чего на себе сделать.

    PHP какой-то странный, но мне понравился JavaScript
    Шикарно, значит есть смысл попробовать NodeJS. Это версия языка (Да, я знаю, что нода это среда а не язык, дайте уже объяснить человеку) расчитаная на составление страниц, как PHP. Это очень мощный инструмент, поняв который, вы вряд ли захотите уйти с него. Он поможет вам писать не только сайты, но и приложения для телефонов / планшетов, программы для ПК, возможно игры (но не стоит. По крайней мере с текущим развитием инструментов), демоны, сервисы, консольные приложения и т.д.

    Они оба мне не нравятся
    Что ж, тогда вам могут приглянуться Python, Ruby - эти два языка более близки к PHP, чем JS.
    Или вы за год стали адептом скорости, и не видите большей радости в жизни чем оптимизация и быстрото рендеренга. Ну тогда вам точно понравятся GO и Rust.
    А может быть Dart к тому временем станет мейн стримом, это уже покажет время.

    Что-бы вы не выбрали, это будет хорошим решением.

    Шаг восьмой
    Как говорится, я просто оставлю это здесь. Сейчас нет смысла объяснять, что это, зачем оно и с чем его едет, вы просто взглянете через год на этот список и все поймете.

    CSS:
    * Sass / Less / Stylus

    JS:
    * CoffeeScript / LiveScript / TypeScript
    * Angular
    * Promise

    NodeJS:
    * NPM
    * Express

    Ускорение работы:
    * Gulp
    * Jade
    * Yo

    Остальное:
    * MongoDB
    * MariaDB
    * RabbitMQ

    Шаг 7 и 8 займут у вас всю жизнь
    Это не в коем случае не значит, что язык будет тем же, просто Язык / Технолигия будут заменяться на другую, а смысл будет тем же. Будут новые технологии, будут новые подходы, новые языки. Будет интересно и весело.
    Ответ написан
    15 комментариев
  • Что за аномалии с массивами в JS?

    HoHsi
    @HoHsi
    1) Не добавляйте элемент в массив через index, используйте #push
    2) Проверяйте на существование переменной, вы каждый раз затираете movies[id];
    3) Если вы используете конструкцию for (var i = 0; i < arr.length; i++) { }, то не вызывайте каждый раз length. Делайте так:
    for (var i = 0, len = arr.length; i < len; i++) { }
    , а еще лучше for (var item in arr) { }

    var arr = [],
        movies = {};
        
    arr.push({
      "id": 22,
      "category": 34,
      "name": "Jel",
      "movie": "Avatar"
    });
    arr.push({
      "id": 34,
      "category": 12,
      "name": "Sali",
      "movie": "Ted 2"
    });
    arr.push({
      "id": 33,
      "category": 34,
      "name": "Chesko",
      "movie": "Avatar"
    });
    arr.push({
      "id": 22,
      "category": 34,
      "name": "Donny",
      "movie": "Avatar"
    });
    
    movies = arr.reduce(function(res, item){
      var id = item.id + "_" + item.movie;
      
      res[ id ] = res[ id ] || {
        "id":     item.id,
        "movie":  item.movie,
      };
    
      res[id].actors = res[id].actors || [];
    
      res[id].actors.push({
        "category": item.category,
        "name":     item.name,
      });
      
      return res;
    }, movies);
    
    console.log(movies);
    Ответ написан
    7 комментариев
  • Как импортировать модуль в ES2015 синтаксисе?

    HoHsi
    @HoHsi
    /**                 V импорт          |   V вызов импорченой функции */
    let config = require("./build/config")(dev, root);
    
    // ES6
    import config from './build/config'
    config = config(dev, root);
    Ответ написан
    Комментировать
  • Как создать JSON поиск?

    HoHsi
    @HoHsi
    function seachArticle( search ){
      var obj = JSON.parse(/* Json */);
      var find;
    
      for (key in obj) {
        if(key === search) {
          find = obj[ key ];
          break;
        }
      }
    
      return find;
    }
    Ответ написан
    Комментировать
  • Как составить регулярное выражение для форматирования номера телефона?

    HoHsi
    @HoHsi
    var REGEXP_PHONE = /(\d{3})(\d{3})(\d{2})(\d{2})/;
    
    var number = '1234567890';
    
    var numberObj = number.match(REGEXP_PHONE);
    
    number = "(" + numberObj[1] + ") " + numberObj[2] + "-" + numberObj[3] + "-" + numberObj[4];
    
    // Или ES6
    number = `(${numberObj[1]}) ${numberObj[2]}-${numberObj[3]}-${numberObj[4]}`;
    Ответ написан
    Комментировать
  • Курсы для фронтендера\дизайнера по завершению которых выдают сертификат (удаленно)?

    HoHsi
    @HoHsi
    Что-бы резюме выглядело солидно, не занимайтесь дро***ом с сертификатами.
    1) Заведите GitHub аккаунт и начните писать открытые библиотечки / сайты. (пусть и корявые, но со временем...)
    2) На том же гите работайте над чужими проектами. Форкайте, пытайтесь запилить свой мердж.
    3) Перестаньте уже заниматься х***ней с сертификатами / тренингами / блицами. Работайте, блеять. Портфолио будет лучше смотреться от реальных работ, а не от макулатуры.
    4) Запилите блог (!!! когда уже сами будете понимать в своей области). Пишите в него статьи, переводы, гайды. Это не столько для окружающих, сколько для вас самих. Ведь как известно ни что так не закрепляет знания. как обучение ими окружающих.

    Ваш кэп.
    Ответ написан
    Комментировать
  • Какую Node.js библиотеку для промисов использовать?

    HoHsi
    @HoHsi Автор вопроса
    Написал тест на производительность.

    # Requires
    Benchmark   = require 'benchmark'
    lagoon      = require 'lagoonjs'
    
    async       = require 'async'
    Q           = require 'q'
    bluebird    = require 'bluebird'
    RSVP        = require 'rsvp'
    whenpromise = require 'when'
    # mpromise    = require 'mpromise' # Не соответствует стандарту
    es6         = require 'es6-promise'
    kew         = require 'kew'
    
    # Init
    logger      = new lagoon.Lagoon()
    
    # Functions
    fakeDelay = (name)-> (delay = 3)-> (callback)=>
        # console.log "[#{ name }] +"
        setTimeout =>
            callback()
        , delay
    
    fakeDelayPromiseQ = (delay)->
        deferred = Q.defer()
    
        fakeDelay("q")(delay) =>
            deferred.resolve()
    
        return deferred.promise
    
    fakeDelayPromiseBB = (delay)->
        new bluebird (resolve, reject)->
            fakeDelay("Bluebird")(delay) =>
                resolve()
    
    fakeDelayPromiseRSVP = (delay)->
        new RSVP.Promise (resolve, reject)->
            fakeDelay("RSVP")(delay) =>
                resolve()
    
    fakeDelayPromiseWhen = (delay)->
        deferred = whenpromise.defer()
    
        fakeDelay("When")(delay) =>
            deferred.resolve()
    
        return deferred.promise
    
    # fakeDelayPromiseM = (delay)->
    #     new mpromise (resolve, reject)->
    #         fakeDelay("M")(delay) =>
    #             resolve()
    
    fakeDelayPromiseES6 = (delay)->
        new es6.Promise (resolve, reject)->
            fakeDelay("ES6")(delay) =>
                resolve()
    
    fakeDelayPromiseKew = (delay)->
        deferred = kew.defer()
    
        fakeDelay("Kew")(delay) =>
            deferred.resolve()
    
        return deferred.promise
    
    # Time
    BenchmarkAsync = (delay, times = 3)-> new Benchmark "Async#parallel X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelay("Async")(delay)
    
            async.parallel queue, =>
                deferred.resolve()
    }
    
    BenchmarkQ = (delay, times = 3)-> new Benchmark "Q#all X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseQ(delay)
    
            Q.all(queue).then =>
                deferred.resolve()
    }
    
    BenchmarkBluebird = (delay, times = 3)-> new Benchmark "Bluebird#all X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseBB(delay)
    
            bluebird.all(queue).then =>
                deferred.resolve()
    }
    
    BenchmarkRSVP = (delay, times = 3)-> new Benchmark "RSVP#all X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseRSVP(delay)
    
            RSVP.all(queue).then =>
                deferred.resolve()
    }
    
    BenchmarkWhen = (delay, times = 3)-> new Benchmark "When#all X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseWhen(delay)
    
            whenpromise.all(queue).then =>
                deferred.resolve()
    }
    
    # BenchmarkM = (delay, times = 3)-> new Benchmark "M#all X #{ times } [#{ delay }ms]", {
    #     defer: true
    #     fn: (deferred)->
    #         queue = []
    #         for [0...times]
    #             queue.push fakeDelayPromiseM(delay)
    
    #         mpromise.all(queue).then =>
    #             deferred.resolve()
    # }
    
    BenchmarkES6 = (delay, times = 3)-> new Benchmark "ES6#all X #{ times } [#{ delay }ms]", {
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseES6(delay)
    
            es6.Promise.all(queue).then =>
                deferred.resolve()
    }
    
    BenchmarkKew = (delay, times = 3)-> new Benchmark "Kew#all X #{ times } [#{ delay }ms]", { 
        defer: true
        fn: (deferred)->
            queue = []
            for [0...times]
                queue.push fakeDelayPromiseKew(delay)
    
            kew.all(queue).then =>
                deferred.resolve()
    }
    
    results = {}
    async.eachLimit [1, 3, 100, 300, 1000, 5000, 10000, 50000, 100000, 1000000], 1, (times, cbt)->
        async.eachLimit [1, 5, 300, 1000], 1, (delay, cbd)->
            suite = new Benchmark.Suite
    
            suite.add BenchmarkAsync( delay, times )
                 .add BenchmarkQ( delay, times )
                 .add BenchmarkBluebird( delay, times )
                 .add BenchmarkRSVP( delay, times )
                 .add BenchmarkWhen( delay, times )
                 .add BenchmarkES6( delay, times )
                 .add BenchmarkKew( delay, times )
                 .on 'cycle', (event)->
                     logger.info String(event.target)
                 .on 'complete', ->
                     logger.warn "Fastest is #{ @.filter('fastest').pluck('name') }"
                     results[ times ] ?= {}
                     results[ times ][ delay ] = @.filter('fastest').pluck('name')
    
                     cbd()
                 .run { 
                     'initCount': 100
                     'async': false
                     'defer': true
                 }
        , ->
            cbt()
    , ->
        logger.log ''
        logger.log ''
        logger.log ''
        for times, resultd of results
            logger.log ''
            for delay, result of resultd
                logger.warn "Fastest is #{ result }"
    Ответ написан