<commit_before>(function($) {
    "use strict";

    /* Handle the case of single digit in a time stamp */
    var formatTimeStamp = function(num) {
        var strnum = num.toString();

        return strnum.length == 1 ? '0' + strnum : strnum;
    };

    /* Transform the timestamps from IST to client browser timestamp */
    var transformTimestamps = function() {
        var clientOffset = new Date().getTimezoneOffset() * 60 * 1000;
        var ISTOffset = -330 * 60 * 1000;
        var convertedTimestamp, ISTTimestamp, d;

        $('.stopstalk-timestamp').each(function(i, td) {
            ISTTimestamp = new Date(td.textContent.replace(/-/g, '/')).getTime();
            d = new Date(ISTTimestamp + ISTOffset - clientOffset);
            convertedTimestamp = [d.getFullYear(),
                d.getMonth() + 1,
                d.getDate()
            ].map(formatTimeStamp).join('-') + " " + [d.getHours(),
                d.getMinutes(),
                d.getSeconds()
            ].map(formatTimeStamp).join(':');
            $(this).html(convertedTimestamp);
        });
    };

    /* Download a submission as a file */
    var downloadSubmission = function(fileName, text) {
        var element = document.createElement('a');

        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    };

    /* Copy the code to the clipboard */
    var copyToClipBoard = function(copyText) {
        var textField = document.createElement('textarea');

        textField.innerHTML = copyText;
        document.body.appendChild(textField);
        textField.select();
        document.execCommand("copy");
        textField.remove();

        $.web2py.flash("Copied to Clipboard");
    };

    /* Escape characters in html to be representable as string */
    var htmlifySubmission = function(solutionCode) {
        return solutionCode.replace(/&/g, "&")
            .replace(/>/g, ">")
            .replace(/</g, "<")
            .replace(/"/g, """).trim(' ');
    };

    /* Get a url parameter by the key from a string url */
    var getParameterByName = function (name, url) {
        if (!url) {
          url = window.location.href;
        }
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }

    $(document).ready(function() {

        var $viewDownloadButton = $('#final-view-download-button'),
            $downloadButton = $('#final-download-button'),
            $downloadModal = $('#download-submission-modal'),
            $viewFileName = $('#view_download_file_name'),
            $viewPreLoader = $('#view-submission-preloader'),
            $viewPre = $('#view-submission-pre'),
            $viewModal = $('#view-submission-modal'),
            $linkToSite = $('#link-to-site');

        transformTimestamps();

        $('.collapsible').collapsible({
            accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
        });

        $('select').material_select();

        $('.tooltipped').tooltip({
            delay: 50
        });

        // Remove focus from any focused element
        if (document.activeElement) {
            document.activeElement.blur();
        }

        $(document).on('mouseenter', 'tr', function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.show();
        });

        $(document).on('mouseleave', 'tr', function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.hide();
        });

        $(document).on('click', '.add-to-todo-list', function() {
            var stopstalkLink = this.parentElement.firstChild["href"],
                problemLink = getParameterByName("plink", stopstalkLink),
                thisElement = this,
                $thisElement = $(this);
            $.ajax({
                url: addTodoURL,
                method: 'POST',
                data: {link: problemLink},
                success: function(response) {
                    var tooltipID = thisElement.getAttribute("data-tooltip-id");
                    $thisElement.remove();
                    $('#' + tooltipID).remove();
                    $.web2py.flash(response);
                },
                error: function(e) {
                    $.web2py.flash("Some error occurred");
                }
            });
        });

        $(document).on('click', '.view-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onViewModalClose = function() {
                $viewDownloadButton.addClass('disabled');
                $viewFileName.val('');
                $viewPreLoader.removeClass('hide');
                $viewPre.addClass('hide');
                $viewPre.removeClass('prettyprint');
                $viewPre.removeClass('prettyprinted');
                $viewPre.html('');
                $('#copy-to-clipboard').addClass('hide');
                $linkToSite.html('');
                $linkToSite.attr('href', '');
            };

            $linkToSite.html('View on ' + site);
            $linkToSite.attr('href', viewLink);

            $viewModal.openModal({
                complete: onViewModalClose
            });

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                var solutionText;

                $viewPreLoader.addClass('hide');
                $viewPre.removeClass('hide');

                $('#copy-to-clipboard').removeClass('hide');

                if (response != -1) {
                    solutionText = htmlifySubmission(response);
                } else {
                    solutionText = "// Unable to retrieve submission from " + site + "\n" + "/* Possible reasons :-\n\t * The submission is from an ongoing contest\n\t * There was some error from our side. \n\t   Please write to us (https://www.stopstalk.com/contact_us)\n */";
                }

                $viewPre.html(solutionText);
                $viewModal.one('click', '#copy-to-clipboard', function() {
                    if (response != -1) {
                        copyToClipBoard(response);
                    } else {
                        copyToClipBoard(solutionText);
                    }
                });

                $viewPre.addClass('prettyprint');
                PR.prettyPrint();
                if (response != -1) {
                    $viewDownloadButton.removeClass('disabled');
                    $viewFileName.on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-view-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-view-download-button', function() {
                        var fileName = $viewFileName.val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $viewModal.closeModal();
                            onViewModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });

        $(document).on('click', '.download-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onDownloadModalClose = function() {
                /* Callback function on Modal close */
                $downloadButton.addClass('disabled');
                $('#file_name').val('');
            };

            $downloadModal.openModal({
                complete: onDownloadModalClose
            });

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                if (response != -1) {
                    $downloadButton.removeClass('disabled');
                    $('#file_name').on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-download-button', function() {
                        var fileName = $('#file_name').val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $downloadModal.closeModal();
                            onDownloadModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });
    });
})(jQuery);<commit_msg>Minor bug fix<commit_after>(function($) {
    "use strict";

    /* Handle the case of single digit in a time stamp */
    var formatTimeStamp = function(num) {
        var strnum = num.toString();

        return strnum.length == 1 ? '0' + strnum : strnum;
    };

    /* Transform the timestamps from IST to client browser timestamp */
    var transformTimestamps = function() {
        var clientOffset = new Date().getTimezoneOffset() * 60 * 1000;
        var ISTOffset = -330 * 60 * 1000;
        var convertedTimestamp, ISTTimestamp, d;

        $('.stopstalk-timestamp').each(function(i, td) {
            ISTTimestamp = new Date(td.textContent.replace(/-/g, '/')).getTime();
            d = new Date(ISTTimestamp + ISTOffset - clientOffset);
            convertedTimestamp = [d.getFullYear(),
                d.getMonth() + 1,
                d.getDate()
            ].map(formatTimeStamp).join('-') + " " + [d.getHours(),
                d.getMinutes(),
                d.getSeconds()
            ].map(formatTimeStamp).join(':');
            $(this).html(convertedTimestamp);
        });
    };

    /* Download a submission as a file */
    var downloadSubmission = function(fileName, text) {
        var element = document.createElement('a');

        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    };

    /* Copy the code to the clipboard */
    var copyToClipBoard = function(copyText) {
        var textField = document.createElement('textarea');

        textField.innerHTML = copyText;
        document.body.appendChild(textField);
        textField.select();
        document.execCommand("copy");
        textField.remove();

        $.web2py.flash("Copied to Clipboard");
    };

    /* Escape characters in html to be representable as string */
    var htmlifySubmission = function(solutionCode) {
        return solutionCode.replace(/&/g, "&")
            .replace(/>/g, ">")
            .replace(/</g, "<")
            .replace(/"/g, """).trim(' ');
    };

    /* Get a url parameter by the key from a string url */
    var getParameterByName = function (name, url) {
        if (!url) {
          url = window.location.href;
        }
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }

    $(document).ready(function() {

        var $viewDownloadButton = $('#final-view-download-button'),
            $downloadButton = $('#final-download-button'),
            $downloadModal = $('#download-submission-modal'),
            $viewFileName = $('#view_download_file_name'),
            $viewPreLoader = $('#view-submission-preloader'),
            $viewPre = $('#view-submission-pre'),
            $viewModal = $('#view-submission-modal'),
            $linkToSite = $('#link-to-site');

        transformTimestamps();

        $("#welcome a").on('touchend', function(){
            window.location.href = $(this).attr('href');
        });

        $('.collapsible').collapsible({
            accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
        });

        $('select').material_select();

        $('.tooltipped').tooltip({
            delay: 50
        });

        // Remove focus from any focused element
        if (document.activeElement) {
            document.activeElement.blur();
        }

        $(document).on('mouseenter', 'tr', function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.show();
        });

        $(document).on('mouseleave', 'tr', function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.hide();
        });

        $(document).on('click', '.add-to-todo-list', function() {
            var stopstalkLink = this.parentElement.firstChild["href"],
                problemLink = getParameterByName("plink", stopstalkLink),
                thisElement = this,
                $thisElement = $(this);
            $.ajax({
                url: addTodoURL,
                method: 'POST',
                data: {link: problemLink},
                success: function(response) {
                    var tooltipID = thisElement.getAttribute("data-tooltip-id");
                    $thisElement.remove();
                    $('#' + tooltipID).remove();
                    $.web2py.flash(response);
                },
                error: function(e) {
                    $.web2py.flash("Some error occurred");
                }
            });
        });

        $(document).on('click', '.view-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onViewModalClose = function() {
                $viewDownloadButton.addClass('disabled');
                $viewFileName.val('');
                $viewPreLoader.removeClass('hide');
                $viewPre.addClass('hide');
                $viewPre.removeClass('prettyprint');
                $viewPre.removeClass('prettyprinted');
                $viewPre.html('');
                $('#copy-to-clipboard').addClass('hide');
                $linkToSite.html('');
                $linkToSite.attr('href', '');
            };

            $linkToSite.html('View on ' + site);
            $linkToSite.attr('href', viewLink);

            $viewModal.openModal({
                complete: onViewModalClose
            });

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                var solutionText;

                $viewPreLoader.addClass('hide');
                $viewPre.removeClass('hide');

                $('#copy-to-clipboard').removeClass('hide');

                if (response != -1) {
                    solutionText = htmlifySubmission(response);
                } else {
                    solutionText = "// Unable to retrieve submission from " + site + "\n" + "/* Possible reasons :-\n\t * The submission is from an ongoing contest\n\t * There was some error from our side. \n\t   Please write to us (https://www.stopstalk.com/contact_us)\n */";
                }

                $viewPre.html(solutionText);
                $viewModal.one('click', '#copy-to-clipboard', function() {
                    if (response != -1) {
                        copyToClipBoard(response);
                    } else {
                        copyToClipBoard(solutionText);
                    }
                });

                $viewPre.addClass('prettyprint');
                PR.prettyPrint();
                if (response != -1) {
                    $viewDownloadButton.removeClass('disabled');
                    $viewFileName.on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-view-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-view-download-button', function() {
                        var fileName = $viewFileName.val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $viewModal.closeModal();
                            onViewModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });

        $(document).on('click', '.download-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onDownloadModalClose = function() {
                /* Callback function on Modal close */
                $downloadButton.addClass('disabled');
                $('#file_name').val('');
            };

            $downloadModal.openModal({
                complete: onDownloadModalClose
            });

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                if (response != -1) {
                    $downloadButton.removeClass('disabled');
                    $('#file_name').on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-download-button', function() {
                        var fileName = $('#file_name').val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $downloadModal.closeModal();
                            onDownloadModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });
    });
})(jQuery);
<|endoftext|>


<commit_before>var _ = require('lodash');
var fs = require('fs');
var moment = require('moment');

var util = require('../../core/util');
var config = util.getConfig();
var dirs = util.dirs();
var log = require(dirs.core + '/log');

var Stitcher = function(batcher) {
  this.batcher = batcher;
}

Stitcher.prototype.ago = function(ts) {
  var now = moment().utc();
  var then = moment.unix(ts).utc();
  return now.diff(then, 'minutes') + ' minutes ago';
}

Stitcher.prototype.verifyExchange = function() {
  var exchangeChecker = require(dirs.core + 'exchangeChecker');
  var slug = config.watch.exchange.toLowerCase();
  var exchange = exchangeChecker.getExchangeCapabilities(slug);

  if(!exchange)
    util.die(`Unsupported exchange: ${slug}`);

  var error = exchangeChecker.cantMonitor(config.watch);
  if(error)
    util.die(error, true);
}

Stitcher.prototype.prepareHistoricalData = function(done) {
  this.verifyExchange();

  // - step 1: check most recent stored candle window
  // - step 2: check oldest trade reachable by API
  // - step 3: see if overlap
  // - step 4: feed candle stream into CandleBatcher

  if(config.tradingAdvisor.historySize === 0)
    return done();

  var requiredHistory = config.tradingAdvisor.candleSize * config.tradingAdvisor.historySize;
  var Reader = require(dirs.plugins + config.adapter + '/reader');

  this.reader = new Reader;

  log.info(
    '\tThe trading method requests',
    requiredHistory,
    'minutes of historic data. Checking availablity..'
  );

  var endTime = moment().utc().startOf('minute');
  var idealStartTime = endTime.clone().subtract(requiredHistory, 'm');

  this.reader.mostRecentWindow(idealStartTime, endTime, function(localData) {
    // now we know what data is locally available, what
    // data would we need from the exchange?
    if(!localData) {
      log.info('\tNo usable local data available, trying to get as much as possible from the exchange..');
      var idealExchangeStartTime = idealStartTime.clone();
      var idealExchangeStartTimeTS = idealExchangeStartTime.unix();
    }
    else {
      log.debug('\tAvailable local data:');
      log.debug('\t\tfrom:', this.ago(localData.from));
      log.debug('\t\tto:', this.ago(localData.to));

      log.info('\tUsable local data available, trying to match with exchange data..')
      // local data is available, we need the next minute

      // make sure we grab back in history far enough
      var secondsOverlap = 60 * 15; // 15 minutes
      var idealExchangeStartTimeTS = localData.to - secondsOverlap;
      var idealExchangeStartTime = moment.unix(idealExchangeStartTimeTS).utc();

      // already set the
      util.setConfigProperty(
        'tradingAdvisor',
        'firstFetchSince',
        idealExchangeStartTimeTS
      );
    }

    // Limit the history Gekko can try to get from the exchange.
    var minutesAgo = endTime.diff(idealExchangeStartTime, 'minutes');
    var maxMinutesAgo = 4 * 60; // 4 hours
    if(minutesAgo > maxMinutesAgo) {
      log.info('\tPreventing Gekko from requesting', minutesAgo, 'minutes of history.');
      idealExchangeStartTime = endTime.clone().subtract(maxMinutesAgo, 'minutes');
      idealExchangeStartTimeTS = idealExchangeStartTime.unix();
    }

    log.debug('\tFetching exchange data since', this.ago(idealExchangeStartTimeTS))
    this.checkExchangeTrades(idealExchangeStartTime, function(err, exchangeData) {
      log.debug('\tAvailable exchange data:');
      log.debug('\t\tfrom:', this.ago(exchangeData.from));
      log.debug('\t\tto:', this.ago(exchangeData.to));

      // in case we have limited local data, and the
      // exchange would offer more than we have: ignore
      // the local data..
      if(
        localData &&
        exchangeData &&
        exchangeData.from < localData.from
      ) {
        log.debug('\tExchange offered more data than locally available. Ignoring local data');
        localData = false;
      }

      var stitchable = localData && exchangeData.from <= localData.to;
      if(stitchable) {
        log.debug('\tStitching datasets');

        // we can combine local data with exchange data
        if(idealStartTime.unix() >= localData.from) {
          log.info(
            '\tFull history locally available.',
            'Seeding the trading method with all required historical candles.'
          );

        } else {

          // stitchable but not enough

          log.info(
            '\tPartial history locally available, but',
            Math.round((localData.from - idealStartTime.unix()) / 60),
            'minutes are missing.')
          log.info('\tSeeding the trading method with',
            'partial historical data (Gekko needs more time before',
            'it can give advice).'
          );
        }

        // seed all historic data up to the point the exchange can provide.
        var from = localData.from;
        var to = moment.unix(exchangeData.from).utc()
          .startOf('minute')
          .subtract(1, 'minute')
          .unix();

        log.debug('\tSeeding with:');
        log.debug('\t\tfrom:', this.ago(from));
        log.debug('\t\tto:', this.ago(to));
        return this.seedLocalData(from, to, done);

      } else if(!stitchable) {
        log.debug('\tUnable to stitch datasets.')
        // we cannot use any local data..
        log.info(
          '\tNot seeding locally available data to the trading method.'
        );

        if(exchangeData.from < idealExchangeStartTimeTS) {
          log.info('\tHowever the exchange returned enough data anyway!');
        } else if(localData) {
          log.info(
            '\tThe exchange does not return enough data.',
            Math.round((localData.from - idealStartTime.unix()) / 60),
            'minutes are still missing.'
          );
        }
      }

      done();

    }.bind(this));
  }.bind(this));
}

Stitcher.prototype.checkExchangeTrades = function(since, next) {
  var provider = config.watch.exchange.toLowerCase();
  var DataProvider = require(util.dirs().gekko + 'exchanges/' + provider);

  var exchangeConfig = config.watch;

  // include trader config if trading is enabled
  if (_.isObject(config.trader) && config.trader.enabled) {
    exchangeConfig = _.extend(config.watch, config.trader);
  }

  var watcher = new DataProvider(exchangeConfig);

  watcher.getTrades(since, function(e, d) {
    if(_.isEmpty(d))
      return util.die(
        `Gekko tried to retrieve data since ${since.format('YYYY-MM-DD HH:mm:ss')}, however
        ${provider} did not return any trades.`
      );

    next(e, {
      from: _.first(d).date,
      to: _.last(d).date
    })
  });
}

Stitcher.prototype.seedLocalData = function(from, to, next) {
  this.reader.get(from, to, 'full', function(err, rows) {
    rows = _.map(rows, row => {
      row.start = moment.unix(row.start);
      return row;
    });

    this.batcher.write(rows);
    this.reader.close();
    next();

  }.bind(this));
}

module.exports = Stitcher;
<commit_msg>Incomplete datasets no longer fool the datastitcher<commit_after>var _ = require('lodash');
var fs = require('fs');
var moment = require('moment');

var util = require('../../core/util');
var config = util.getConfig();
var dirs = util.dirs();
var log = require(dirs.core + '/log');

var Stitcher = function(batcher) {
  this.batcher = batcher;
}

Stitcher.prototype.ago = function(ts) {
  var now = moment().utc();
  var then = moment.unix(ts).utc();
  return now.diff(then, 'minutes') + ' minutes ago';
}

Stitcher.prototype.verifyExchange = function() {
  var exchangeChecker = require(dirs.core + 'exchangeChecker');
  var slug = config.watch.exchange.toLowerCase();
  var exchange = exchangeChecker.getExchangeCapabilities(slug);

  if(!exchange)
    util.die(`Unsupported exchange: ${slug}`);

  var error = exchangeChecker.cantMonitor(config.watch);
  if(error)
    util.die(error, true);
}

Stitcher.prototype.prepareHistoricalData = function(done) {
  this.verifyExchange();

  // - step 1: check most recent stored candle window
  // - step 2: check oldest trade reachable by API
  // - step 3: see if overlap
  // - step 4: feed candle stream into CandleBatcher

  if(config.tradingAdvisor.historySize === 0)
    return done();

  var requiredHistory = config.tradingAdvisor.candleSize * config.tradingAdvisor.historySize;
  var Reader = require(dirs.plugins + config.adapter + '/reader');

  this.reader = new Reader;

  log.info(
    '\tThe trading method requests',
    requiredHistory,
    'minutes of historic data. Checking availablity..'
  );

  var endTime = moment().utc().startOf('minute');
  var idealStartTime = endTime.clone().subtract(requiredHistory, 'm');

  this.reader.mostRecentWindow(idealStartTime, endTime, function(localData) {
    // now we know what data is locally available, what
    // data would we need from the exchange?
    if(!localData) {
      log.info('\tNo usable local data available, trying to get as much as possible from the exchange..');
      var idealExchangeStartTime = idealStartTime.clone();
      var idealExchangeStartTimeTS = idealExchangeStartTime.unix();
    }
    else if (idealStartTime.unix() < localData.from) {
      log.info('\tLocal data is still too recent, trying to get as much as possible from the exchange');
      var idealExchangeStartTime = idealStartTime.clone();
      var idealExchangeStartTimeTS = idealExchangeStartTime.unix();
    }
    else {
      log.debug('\tAvailable local data:');
      log.debug('\t\tfrom:', this.ago(localData.from));
      log.debug('\t\tto:', this.ago(localData.to));

      log.info('\tUsable local data available, trying to match with exchange data..')
      // local data is available, we need the next minute

      // make sure we grab back in history far enough
      var secondsOverlap = 60 * 15; // 15 minutes
      var idealExchangeStartTimeTS = localData.to - secondsOverlap;
      var idealExchangeStartTime = moment.unix(idealExchangeStartTimeTS).utc();

      // already set the
      util.setConfigProperty(
        'tradingAdvisor',
        'firstFetchSince',
        idealExchangeStartTimeTS
      );
    }

    // Limit the history Gekko can try to get from the exchange.
    var minutesAgo = endTime.diff(idealExchangeStartTime, 'minutes');
    var maxMinutesAgo = 4 * 60; // 4 hours
    if(minutesAgo > maxMinutesAgo) {
      log.info('\tPreventing Gekko from requesting', minutesAgo, 'minutes of history.');
      idealExchangeStartTime = endTime.clone().subtract(maxMinutesAgo, 'minutes');
      idealExchangeStartTimeTS = idealExchangeStartTime.unix();
    }

    log.debug('\tFetching exchange data since', this.ago(idealExchangeStartTimeTS))
    this.checkExchangeTrades(idealExchangeStartTime, function(err, exchangeData) {
      log.debug('\tAvailable exchange data:');
      log.debug('\t\tfrom:', this.ago(exchangeData.from));
      log.debug('\t\tto:', this.ago(exchangeData.to));

      // in case we have limited local data, and the
      // exchange would offer more than we have: ignore
      // the local data..
      if(
        localData &&
        exchangeData &&
        exchangeData.from < localData.from
      ) {
        log.debug('\tExchange offered more data than locally available. Ignoring local data');
        localData = false;
      }

      var stitchable = localData && exchangeData.from <= localData.to;
      if(stitchable) {
        log.debug('\tStitching datasets');

        // we can combine local data with exchange data
        if(idealStartTime.unix() >= localData.from) {
          log.info(
            '\tFull history locally available.',
            'Seeding the trading method with all required historical candles.'
          );

        } else {

          // stitchable but not enough

          log.info(
            '\tPartial history locally available, but',
            Math.round((localData.from - idealStartTime.unix()) / 60),
            'minutes are missing.')
          log.info('\tSeeding the trading method with',
            'partial historical data (Gekko needs more time before',
            'it can give advice).'
          );
        }

        // seed all historic data up to the point the exchange can provide.
        var from = localData.from;
        var to = moment.unix(exchangeData.from).utc()
          .startOf('minute')
          .subtract(1, 'minute')
          .unix();

        log.debug('\tSeeding with:');
        log.debug('\t\tfrom:', this.ago(from));
        log.debug('\t\tto:', this.ago(to));
        return this.seedLocalData(from, to, done);

      } else if(!stitchable) {
        log.debug('\tUnable to stitch datasets.')
        // we cannot use any local data..
        log.info(
          '\tNot seeding locally available data to the trading method.'
        );

        if(exchangeData.from < idealExchangeStartTimeTS) {
          log.info('\tHowever the exchange returned enough data anyway!');
        } else if(localData) {
          log.info(
            '\tThe exchange does not return enough data.',
            Math.round((localData.from - idealStartTime.unix()) / 60),
            'minutes are still missing.'
          );
        }
      }

      done();

    }.bind(this));
  }.bind(this));
}

Stitcher.prototype.checkExchangeTrades = function(since, next) {
  var provider = config.watch.exchange.toLowerCase();
  var DataProvider = require(util.dirs().gekko + 'exchanges/' + provider);

  var exchangeConfig = config.watch;

  // include trader config if trading is enabled
  if (_.isObject(config.trader) && config.trader.enabled) {
    exchangeConfig = _.extend(config.watch, config.trader);
  }

  var watcher = new DataProvider(exchangeConfig);

  watcher.getTrades(since, function(e, d) {
    if(_.isEmpty(d))
      return util.die(
        `Gekko tried to retrieve data since ${since.format('YYYY-MM-DD HH:mm:ss')}, however
        ${provider} did not return any trades.`
      );

    next(e, {
      from: _.first(d).date,
      to: _.last(d).date
    })
  });
}

Stitcher.prototype.seedLocalData = function(from, to, next) {
  this.reader.get(from, to, 'full', function(err, rows) {
    rows = _.map(rows, row => {
      row.start = moment.unix(row.start);
      return row;
    });

    this.batcher.write(rows);
    this.reader.close();
    next();

  }.bind(this));
}

module.exports = Stitcher;
<|endoftext|>


<commit_before>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.URL = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var helper = require("./helper");

function URL(locator, options, override) {
	var self = this, own = self;

	if(typeof locator === "string") {
		locator = String(locator || "").trim();

		if(!locator) {
			throw new Error("Invalid locator:", locator);
		}

		options = helper.merge({/* ∅ */}, options);

		var capture = URL.pattern.exec(locator);

		if(!capture) {
			throw new Error("Invalid URL: " + locator);
		}

		capture = capture.slice(1);

		URL.parts.forEach(function(part, index) {
			var value = override && (part in options) ? options[part] : capture[index] || options[part];
			if(value !== undefined) {
				own[part] = value;
			}
		});

		if(typeof own.query === "string") {
			own.query = URL.parseQueryString(own.query);
		}

		// If not overriding, let's complete the query parameters:
		if(!override && own.query !== options.query) {
			if(typeof options.query === "string") {
				options.query = URL.parseQueryString(options.query);
			}
			own.query = helper.merge({}, own.query, options.query);
		}
	}
	else {
		options = locator;

		options.path = options.path || "/";

		if(options.protocol && !options.host) {
			throw new Error("Missing URL parts: " + JSON.stringify(options));
		}

		URL.parts.forEach(function(part, index) {
			if(part in options) {
				own[part] = options[part] && String(options[part]);
			}
		});

		if(typeof own.query === "string") {
			own.query = URL.parseQueryString(own.query);
		}
	}

	if(own.port !== undefined && typeof own.port !== "number") {
		own.port = Number(own.port);
	}
}

URL.prototype.toString = function() {
	var self = this, own = self;

	var result = "";

	if(own.host) {
		own.protocol && (result += own.protocol + ":");
		result += "//" + own.host;
		if(own.port && own.port !== 80) {
			result += ":" + own.port;
		}
	}

	result += own.path || (own.query || own.fragment) && "/" || "";

	if(own.query) {
		var queryString = URL.makeQueryString(own.query);
		if(queryString) {
			result += "?" + queryString;
		}
	}

	if(own.fragment) {
		result += "#" + own.fragment;
	}

	return result;
};

// Cf. [RFC 3986](http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax)
URL.pattern = /^(?:(?:(\w+):)?\/\/(?:(\w+):(\w+)@)?([.\-\w]+)(?::(\d+))?)?(?:(\/[^\?#]*)(?:\?([^#]+))?(?:#(.+))?)?$/;

URL.parts = ["protocol", "user", "password", "host", "port", "path", "query", "fragment"];

URL.parseQueryString = function(queryString) {
	var query = {}, capture;
	var pattern = /([^&=]+)=?([^&]*)/g;

	// Here we need to use the same pattern instance for every iterations, otherwise it won't stop...
	while(queryString && (capture = pattern.exec(queryString))) { // assignment
		query[decode(capture[1])] = decode(capture[2]) || undefined;
	}

	// Decode URI components and replace "+" occurrences with spaces.
	function decode(string) {
		return decodeURIComponent(string.replace(/\+/g, " "));
	}

	return query;
};

URL.makeQueryString = function(query) {
	var pairs = [];
	for(var parameter in query) {
		if(query.hasOwnProperty(parameter)) {
			var value = query[parameter];
			pairs.push(encodeURIComponent(parameter) + (value ? "=" + encodeURIComponent(value) : ""));
		}
	}

	return pairs.join("&");
};

module.exports = URL;
},{"./helper":2}],2:[function(require,module,exports){
function merge(object/*, source, ...*/) {
	Array.prototype.slice.call(arguments, 1).forEach(function(source) {
		if(Array.isArray(object) && Array.isArray(source)) {
			source.forEach(function(value) {
				if(!~object.indexOf(value)) {
					object.push(value);
				}
			});
		}
		else {
			for(var property in source) {
				if(source.hasOwnProperty(property)) {
					if(isObject(object[property]) && isObject(source[property])) {
						object[property] = merge(object[property], source[property]);
					}
					else {
						object[property] = source[property];
					}
				}
			}
		}
	});

	return object;
}

function isObject(value) {
	return value && typeof value === "object";
}

module.exports = {
	merge: merge,
	isObject: isObject
};
},{}]},{},[1])(1)
});<commit_msg>Woops, forgot Bower...<commit_after>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.URL = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var helper = require("./helper");

function URL(locator, options, overwrite) {
	var self = this, own = self;

	if(typeof locator === "string") {
		locator = String(locator || "").trim();

		if(!locator) {
			throw new Error("Invalid locator:", locator);
		}

		options = helper.merge({/* ∅ */}, options);

		var capture = URL.pattern.exec(locator);

		if(!capture) {
			throw new Error("Invalid URL: " + locator);
		}

		capture = capture.slice(1);

		URL.parts.forEach(function(part, index) {
			var value = overwrite && (part in options) ? options[part] : capture[index] || options[part];
			if(value !== undefined) {
				own[part] = value;
			}
		});

		if(typeof own.query === "string") {
			own.query = URL.parseQueryString(own.query);
		}

		// If not overriding, let's complete the query parameters:
		if(!overwrite && own.query !== options.query) {
			if(typeof options.query === "string") {
				options.query = URL.parseQueryString(options.query);
			}
			own.query = helper.merge({}, own.query, options.query);
		}
	}
	else {
		options = locator;

		if(options.protocol && !options.host
			|| options.port && !options.host
			|| options.user && !options.host
			|| options.password && !options.user) {
			throw new Error("Missing URL parts: " + JSON.stringify(options));
		}

		URL.parts.forEach(function(part, index) {
			if(part in options) {
				own[part] = options[part] && String(options[part]);
			}
		});

		if(typeof own.query === "string") {
			own.query = URL.parseQueryString(own.query);
		}
	}

	own.path = own.path || "/";

	if(own.port !== undefined && typeof own.port !== "number") {
		own.port = Number(own.port);
	}
}

URL.prototype.toString = function() {
	var self = this, own = self;

	var result = "";

	if(own.host) {
		own.protocol && (result += own.protocol + ":");
		result += "//";
		if(own.user) {
			result += own.user;
			if(own.password) {
				result += ":" + own.password;
			}
			result += "@"
		}
		result += own.host;
		if(own.port && own.port !== 80) {
			result += ":" + own.port;
		}
	}

	result += own.path;

	if(own.query) {
		result += "?" + URL.makeQueryString(own.query);
	}

	if(own.fragment) {
		result += "#" + own.fragment;
	}

	return result;
};

// Cf. [RFC 3986](http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax)
URL.pattern = /^(?:(?:(\w+):)?\/\/(?:(\w+)(?::(\w+))?@)?([.\-\w]+)(?::(\d+))?)?(?:(\/[^\?#]*)(?:\?([^#]+))?(?:#(.+))?)?$/;

URL.parts = ["protocol", "user", "password", "host", "port", "path", "query", "fragment"];

URL.parseQueryString = function(queryString) {
	var query = {}, capture;
	var pattern = /([^&=]+)=?([^&]*)/g;

	// Here we need to use the same pattern instance for every iterations, otherwise it won't stop...
	while(queryString && (capture = pattern.exec(queryString))) { // assignment
		query[decode(capture[1])] = decode(capture[2]) || undefined;
	}

	// Decode URI components and replace "+" occurrences with spaces.
	function decode(string) {
		return decodeURIComponent(string.replace(/\+/g, " "));
	}

	return query;
};

URL.makeQueryString = function(query) {
	var pairs = [];
	for(var parameter in query) {
		var value = query[parameter];
		pairs.push(encodeURIComponent(parameter) + (value ? "=" + encodeURIComponent(value) : ""));
	}

	return pairs.join("&");
};

module.exports = URL;
},{"./helper":2}],2:[function(require,module,exports){
function merge(object/*, source, ...*/) {
	Array.prototype.slice.call(arguments, 1).forEach(function(source) {
		if(Array.isArray(object) && Array.isArray(source)) {
			source.forEach(function(value) {
				if(!~object.indexOf(value)) {
					object.push(value);
				}
			});
		}
		else {
			for(var property in source) {
				if(source.hasOwnProperty(property)) {
					if(isObject(object[property]) && isObject(source[property])) {
						object[property] = merge(object[property], source[property]);
					}
					else {
						object[property] = source[property];
					}
				}
			}
		}
	});

	return object;
}

function isObject(value) {
	return value && typeof value === "object";
}

module.exports = {
	merge: merge,
	isObject: isObject
};
},{}]},{},[1])(1)
});<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { injectIntl, FormattedMessage } from 'react-intl';
import { Grid, Row, Col } from 'react-flexbox-grid/lib';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import withIntlForm from '../../common/hocs/IntlForm';
import withAsyncData from '../../common/hocs/AsyncDataContainer';
import AppButton from '../../common/AppButton';
import StoryFeedbackRow from './StoryFeedbackRow';
import { goToTopicStep, fetchStorySampleByQuery } from '../../../actions/topicActions';

const NUM_TO_SHOW = 30;
const VALIDATION_CUTOFF = 0.9;

const localMessages = {
  warningTitle: { id: 'topic.modify.validate.warningTitle', defaultMessage: 'Relevance Low' },
  warning: { id: 'topic.modify.validate.warning',
    defaultMessage: 'It seems that not enough of the stories are relevant to the topic you\'re researching. We recommend at least 90% of stories from the list presented must be relevant for the topic to work well. We suggest going back to your query and try either changing the search terms (to narrow in a bit more), your time period (to focus around any key events), or media sources (to specify media from the place you care about). If you\'re unable to generate relevant stories after that, please feel free to reach us at support@mediacloud.org for help.' },
  randomStory: { id: 'topic.modify.validate.randomStory', defaultMessage: 'Random Story' },
  usefulStory: { id: 'topic.modify.validate.randomStory', defaultMessage: 'Is this Relevant?' },
  prev: { id: 'topic.modify.warning.prev', defaultMessage: 'back to preview' },
  next: { id: 'topic.modify.warning.next', defaultMessage: 'review and confirm' },
  warningIgnore: { id: 'topic.modify.warning.warningIgnore', defaultMessage: 'Ignore and {mode} Topic Anway' },
  warningOk: { id: 'topic.modify.warning.warningOk', defaultMessage: 'I\'ll edit my seed query' },
};

class TopicValidateContainer extends React.Component {
  state = {
    matchCount: 0,
    warningOpen: false,
  };

  handleWarningOk = () => {
    const { handleEditSeedQueryRequest } = this.props;
    this.setState({ warningOpen: false });
    handleEditSeedQueryRequest();
  }

  handleWarningIgnore = () => {
    const { onStepChange, mode } = this.props;
    onStepChange(mode, 3);
  }

  handleYesClick = (options, prevSelection) => {
    if (prevSelection === options.match) {
      this.setState(prevState => ({ matchCount: prevState.matchCount - 1 }));
    } else {
      this.setState(prevState => ({ matchCount: prevState.matchCount + 1 }));
    }
  }

  handleNoClick = (options, prevSelection) => {
    if (prevSelection === options.match) {
      this.setState(prevState => ({ matchCount: prevState.matchCount - 1 }));
    }
  }

  handleConfirm = () => {
    const { onStepChange, total, mode } = this.props;
    if (this.state.matchCount >= (VALIDATION_CUTOFF * total)) {
      onStepChange(mode, 3);
    } else {
      this.setState({ warningOpen: true });
    }
  }

  render = () => {
    const { onStepChange, stories, mode, currentStepText } = this.props;
    const { formatMessage } = this.props.intl;

    return (
      <Grid>

{currentStepText.title}

{currentStepText.description}

        <Row start="lg" className="topic-modify-sample-story-table">
          <Col lg={12}>
            <Row start="lg" className="topic-modify-sample-story-table-header">
              <Col lg={8} className="topic-modify-story-title-col">
                <FormattedMessage {...localMessages.randomStory} />
              </Col>
              <Col lg={4} className="topic-modify-match-col">
                <FormattedMessage {...localMessages.usefulStory} />
              </Col>
            </Row>
          </Col>
          <Col lg={12}>
            <Row start="lg" className="topic-modify-sample-story-container">
              <Col lg={12}>
                {stories.map(story => (
                  <StoryFeedbackRow
                    key={story.stories_id}
                    story={story}
                    maxTitleLength={85}
                    handleYesClick={this.handleYesClick}
                    handleNoClick={this.handleNoClick}
                  />
                ))}
              </Col>
            </Row>
          </Col>
        </Row>

        <Row>
          <Col lg={12} md={12} sm={12}>
            <AppButton label={formatMessage(localMessages.prev)} onClick={() => onStepChange(mode, 1)} />

            <AppButton
              type="submit"
              label={formatMessage(localMessages.next)}
              primary
              onClick={() => this.handleConfirm(mode)}
            />
          </Col>
        </Row>
        <Dialog
          disableBackdropClick
          disableEscapeKeyDown
          aria-labelledby="confirmation-dialog-title"
          open={this.state.warningOpen}
          onClose={this.handleWarningOk}
        >
          <DialogTitle id="confirmation-dialog-title">
            <FormattedMessage {...localMessages.warningTitle} />
          </DialogTitle>
          <DialogContent>

              <FormattedMessage {...localMessages.warning} />

          </DialogContent>
          <DialogActions>
            <AppButton label={formatMessage(localMessages.warningIgnore, { mode })} onClick={this.handleWarningIgnore}>
              <FormattedMessage {...localMessages.warningIgnore} values={{ mode }} />
            </AppButton>
            <AppButton label={formatMessage(localMessages.warningOk)} onClick={this.handleWarningOk} primary>
              <FormattedMessage {...localMessages.warningOk} />
            </AppButton>
          </DialogActions>
        </Dialog>
      </Grid>
    );
  }
}

TopicValidateContainer.propTypes = {
  // from parent
  location: PropTypes.object.isRequired,
  currentStepText: PropTypes.object,
  mode: PropTypes.string.isRequired,
  onStepChange: PropTypes.func.isRequired,
  // form composition
  intl: PropTypes.object.isRequired,
  // from state
  fetchStatus: PropTypes.string.isRequired,
  total: PropTypes.number.isRequired,
  stories: PropTypes.array.isRequired,
  // from dispatch
  handleEditSeedQueryRequest: PropTypes.func.isRequired,
  // from form
  formData: PropTypes.object,
};

const mapStateToProps = state => ({
  formData: state.form.topicForm.values,
  currentStep: state.topics.modify.preview.workflow.currentStep,
  fetchStatus: state.topics.modify.preview.matchingStories.fetchStatus,
  total: state.topics.modify.preview.matchingStories.total,
  stories: state.topics.modify.preview.matchingStories.list,
});

const mapDispatchToProps = dispatch => ({
  handleEditSeedQueryRequest: () => {
    dispatch(goToTopicStep(0));
  },
});

const fetchAsyncData = (dispatch, { formData }) => {
  const infoForQuery = {
    q: formData.solr_seed_query,
    start_date: formData.start_date,
    end_date: formData.end_date,
    rows: NUM_TO_SHOW,
  };
  infoForQuery['collections[]'] = [];
  infoForQuery['sources[]'] = [];

  if ('sourcesAndCollections' in formData) { // in FieldArrays on the form
    infoForQuery['collections[]'] = formData.sourcesAndCollections.map(s => s.tags_id);
    infoForQuery['sources[]'] = formData.sourcesAndCollections.map(s => s.media_id);
  }
  dispatch(fetchStorySampleByQuery(infoForQuery));
};

export default
injectIntl(
  withIntlForm(
    connect(mapStateToProps, mapDispatchToProps)(
      withAsyncData(fetchAsyncData)(
        TopicValidateContainer
      )
    )
  )
);
<commit_msg>fix typo<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { injectIntl, FormattedMessage } from 'react-intl';
import { Grid, Row, Col } from 'react-flexbox-grid/lib';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import withIntlForm from '../../common/hocs/IntlForm';
import withAsyncData from '../../common/hocs/AsyncDataContainer';
import AppButton from '../../common/AppButton';
import StoryFeedbackRow from './StoryFeedbackRow';
import { goToTopicStep, fetchStorySampleByQuery } from '../../../actions/topicActions';

const NUM_TO_SHOW = 30;
const VALIDATION_CUTOFF = 0.9;

const localMessages = {
  warningTitle: { id: 'topic.modify.validate.warningTitle', defaultMessage: 'Relevance Low' },
  warning: { id: 'topic.modify.validate.warning',
    defaultMessage: 'It seems that not enough of the stories are relevant to the topic you\'re researching. We recommend at least 90% of stories from the list presented must be relevant for the topic to work well. We suggest going back to your query and try either changing the search terms (to narrow in a bit more), your time period (to focus around any key events), or media sources (to specify media from the place you care about). If you\'re unable to generate relevant stories after that, please feel free to reach us at support@mediacloud.org for help.' },
  randomStory: { id: 'topic.modify.validate.randomStory', defaultMessage: 'Random Story' },
  usefulStory: { id: 'topic.modify.validate.randomStory', defaultMessage: 'Is this Relevant?' },
  prev: { id: 'topic.modify.warning.prev', defaultMessage: 'back to preview' },
  next: { id: 'topic.modify.warning.next', defaultMessage: 'review and confirm' },
  warningIgnore: { id: 'topic.modify.warning.warningIgnore', defaultMessage: 'Ignore and {mode} Topic Anyway' },
  warningOk: { id: 'topic.modify.warning.warningOk', defaultMessage: 'I\'ll edit my seed query' },
};

class TopicValidateContainer extends React.Component {
  state = {
    matchCount: 0,
    warningOpen: false,
  };

  handleWarningOk = () => {
    const { handleEditSeedQueryRequest } = this.props;
    this.setState({ warningOpen: false });
    handleEditSeedQueryRequest();
  }

  handleWarningIgnore = () => {
    const { onStepChange, mode } = this.props;
    onStepChange(mode, 3);
  }

  handleYesClick = (options, prevSelection) => {
    if (prevSelection === options.match) {
      this.setState(prevState => ({ matchCount: prevState.matchCount - 1 }));
    } else {
      this.setState(prevState => ({ matchCount: prevState.matchCount + 1 }));
    }
  }

  handleNoClick = (options, prevSelection) => {
    if (prevSelection === options.match) {
      this.setState(prevState => ({ matchCount: prevState.matchCount - 1 }));
    }
  }

  handleConfirm = () => {
    const { onStepChange, total, mode } = this.props;
    if (this.state.matchCount >= (VALIDATION_CUTOFF * total)) {
      onStepChange(mode, 3);
    } else {
      this.setState({ warningOpen: true });
    }
  }

  render = () => {
    const { onStepChange, stories, mode, currentStepText } = this.props;
    const { formatMessage } = this.props.intl;

    return (
      <Grid>

{currentStepText.title}

{currentStepText.description}

        <Row start="lg" className="topic-modify-sample-story-table">
          <Col lg={12}>
            <Row start="lg" className="topic-modify-sample-story-table-header">
              <Col lg={8} className="topic-modify-story-title-col">
                <FormattedMessage {...localMessages.randomStory} />
              </Col>
              <Col lg={4} className="topic-modify-match-col">
                <FormattedMessage {...localMessages.usefulStory} />
              </Col>
            </Row>
          </Col>
          <Col lg={12}>
            <Row start="lg" className="topic-modify-sample-story-container">
              <Col lg={12}>
                {stories.map(story => (
                  <StoryFeedbackRow
                    key={story.stories_id}
                    story={story}
                    maxTitleLength={85}
                    handleYesClick={this.handleYesClick}
                    handleNoClick={this.handleNoClick}
                  />
                ))}
              </Col>
            </Row>
          </Col>
        </Row>

        <Row>
          <Col lg={12} md={12} sm={12}>
            <AppButton label={formatMessage(localMessages.prev)} onClick={() => onStepChange(mode, 1)} />

            <AppButton
              type="submit"
              label={formatMessage(localMessages.next)}
              primary
              onClick={() => this.handleConfirm(mode)}
            />
          </Col>
        </Row>
        <Dialog
          disableBackdropClick
          disableEscapeKeyDown
          aria-labelledby="confirmation-dialog-title"
          open={this.state.warningOpen}
          onClose={this.handleWarningOk}
        >
          <DialogTitle id="confirmation-dialog-title">
            <FormattedMessage {...localMessages.warningTitle} />
          </DialogTitle>
          <DialogContent>

              <FormattedMessage {...localMessages.warning} />

          </DialogContent>
          <DialogActions>
            <AppButton label={formatMessage(localMessages.warningIgnore, { mode })} onClick={this.handleWarningIgnore}>
              <FormattedMessage {...localMessages.warningIgnore} values={{ mode }} />
            </AppButton>
            <AppButton label={formatMessage(localMessages.warningOk)} onClick={this.handleWarningOk} primary>
              <FormattedMessage {...localMessages.warningOk} />
            </AppButton>
          </DialogActions>
        </Dialog>
      </Grid>
    );
  }
}

TopicValidateContainer.propTypes = {
  // from parent
  location: PropTypes.object.isRequired,
  currentStepText: PropTypes.object,
  mode: PropTypes.string.isRequired,
  onStepChange: PropTypes.func.isRequired,
  // form composition
  intl: PropTypes.object.isRequired,
  // from state
  fetchStatus: PropTypes.string.isRequired,
  total: PropTypes.number.isRequired,
  stories: PropTypes.array.isRequired,
  // from dispatch
  handleEditSeedQueryRequest: PropTypes.func.isRequired,
  // from form
  formData: PropTypes.object,
};

const mapStateToProps = state => ({
  formData: state.form.topicForm.values,
  currentStep: state.topics.modify.preview.workflow.currentStep,
  fetchStatus: state.topics.modify.preview.matchingStories.fetchStatus,
  total: state.topics.modify.preview.matchingStories.total,
  stories: state.topics.modify.preview.matchingStories.list,
});

const mapDispatchToProps = dispatch => ({
  handleEditSeedQueryRequest: () => {
    dispatch(goToTopicStep(0));
  },
});

const fetchAsyncData = (dispatch, { formData }) => {
  const infoForQuery = {
    q: formData.solr_seed_query,
    start_date: formData.start_date,
    end_date: formData.end_date,
    rows: NUM_TO_SHOW,
  };
  infoForQuery['collections[]'] = [];
  infoForQuery['sources[]'] = [];

  if ('sourcesAndCollections' in formData) { // in FieldArrays on the form
    infoForQuery['collections[]'] = formData.sourcesAndCollections.map(s => s.tags_id);
    infoForQuery['sources[]'] = formData.sourcesAndCollections.map(s => s.media_id);
  }
  dispatch(fetchStorySampleByQuery(infoForQuery));
};

export default
injectIntl(
  withIntlForm(
    connect(mapStateToProps, mapDispatchToProps)(
      withAsyncData(fetchAsyncData)(
        TopicValidateContainer
      )
    )
  )
);
<|endoftext|>


<commit_before>var compose_fade = (function () {

var exports = {};

var focused_recipient;
var normal_display = false;

exports.set_focused_recipient = function (msg_type) {
    if (msg_type === undefined) {
        focused_recipient = undefined;
    }

    // Construct focused_recipient as a mocked up element which has all the
    // fields of a message used by util.same_recipient()
    focused_recipient = {
        type: msg_type
    };

    if (focused_recipient.type === "stream") {
        focused_recipient.stream = $('#stream').val();
        focused_recipient.subject = $('#subject').val();
    } else {
        // Normalize the recipient list so it matches the one used when
        // adding the message (see add_message_metadata(), zulip.js).
        focused_recipient.reply_to = util.normalize_recipients(
                $('#private_message_recipient').val());
    }
};

function _display_messages_normally() {
    rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row")
                                               .removeClass("faded").removeClass("unfaded");

    normal_display = true;
    ui.update_floating_recipient_bar();
}

function _display_users_normally() {
    if (!feature_flags.fade_users_when_composing) {
        return;
    }
    $('.user_sidebar_entry').removeClass('faded').removeClass('unfaded');
}

function _fade_messages() {
    var i;
    var all_elts = rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row");
    var should_fade_message = false;

    normal_display = false;

    // Note: The below algorithm relies on the fact that all_elts is
    // sorted as it would be displayed in the message view
    for (i = 0; i < all_elts.length; i++) {
        var elt = $(all_elts[i]);
        if (elt.hasClass("recipient_row")) {
            should_fade_message = !util.same_recipient(focused_recipient, current_msg_list.get(rows.id(elt)));
        }

        if (should_fade_message) {
            elt.removeClass("unfaded").addClass("faded");
        } else {
            elt.removeClass("faded").addClass("unfaded");
        }
    }

    ui.update_floating_recipient_bar();
}

exports.would_receive_message = function (email) {
    // Given the current focused_recipient, this function returns true if
    // the user in question would definitely receive this message, false if
    // they would definitely not receive this message, and undefined if we
    // don't know (e.g. the recipient is a stream we're not subscribed to).
    //
    // Yes it's slightly weird to have three return values, but this will be
    // helpful if we want to emphasize the '.unfaded' class later (applied
    // to users who will definitely receive the message).

    if (email === page_params.email) {
        // We never want to fade you yourself, so pretend it's true even if
        // it's not.
        return true;
    }

    if (focused_recipient.type === 'stream') {
        return stream_data.user_is_subscribed(focused_recipient.stream, email);
    }

    // PM, so check if the given email is in the recipients list.
    var recipients = focused_recipient.reply_to.split(',');
    return recipients.indexOf(email) !== -1;
};

function _fade_users() {
    if (!feature_flags.fade_users_when_composing) {
        return;
    }
    _.forEach($('.user_sidebar_entry'), function (elt) {
        elt = $(elt);
        var would_receive = exports.would_receive_message(elt.attr('data-email'));
        if (would_receive === true) {
            elt.addClass('unfaded').removeClass('faded');
        } else if (would_receive === false) {
            elt.addClass('faded').removeClass('unfaded');
        } else {
            elt.removeClass('faded').removeClass('unfaded');
        }
    });
}

function _want_normal_display() {
    // If we're not composing show a normal display.
    if (focused_recipient === undefined) {
        return true;
    }

    // If the user really hasn't specified anything let, then we want a normal display
    if ((focused_recipient.type === "stream" && focused_recipient.subject === "") ||
        (focused_recipient.type === "private" && focused_recipient.reply_to === "")) {
        return true;
    }

    return false;
}

function _update_faded_messages() {
    // See also update_faded_messages(), which just wraps this with a debounce.
    // FIXME: This fades users too now, as well as messages, so should have
    // a better name.
    if (_want_normal_display()) {
        if (!normal_display) {
            _display_messages_normally();
            _display_users_normally();
        }
    }
    else {
        _fade_messages();
        _fade_users();
    }
}

// This one only updates the users, not both, like update_faded_messages.
// This is for when new presence information comes in, redrawing the presence
// list.
exports.update_faded_users = function () {
    if (_want_normal_display()) {
        _display_users_normally();
    } else {
        _fade_users();
    }
};

// See trac #1633.  For fast typists, calls to _update_faded_messages can
// cause typing sluggishness.
exports.update_faded_messages = _.debounce(_update_faded_messages, 50);

exports.start_compose = function (msg_type) {
    exports.set_focused_recipient(msg_type);
    _update_faded_messages();
};

exports.clear_compose = function () {
    focused_recipient = undefined;
    _display_messages_normally();
    _display_users_normally();
};

exports.update_message_list = function () {
    if (_want_normal_display()) {
       _display_messages_normally();
    }
    else {
        _fade_messages();
    }
};

exports.update_rendered_messages = function (messages, get_elements) {
    if (_want_normal_display()) {
        return;
    }

    // This loop is superficially similar to some code in _fade_messages, but an
    // important difference here is that we look at each message individually, whereas
    // the other code takes advantage of blocks beneath recipient bars.
    //
    // get_elements() is plural, because we can get up to two elements:
    //   the message (always)
    //   the recipient bar (sometimes)
    _.each(messages, function (message) {
        var elts = get_elements(message);
        var should_fade_message = !util.same_recipient(focused_recipient, message);

        _.each(elts, function (elt) {
            if (should_fade_message) {
                elt.removeClass("unfaded").addClass("faded");
            } else {
                elt.removeClass("faded").addClass("unfaded");
            }
        });
    });
};

$(function () {
    $(document).on('peer_subscribe.zulip', function (e) {
        exports.update_faded_users();
    });
    $(document).on('peer_unsubscribe.zulip', function (e) {
        exports.update_faded_users();
    });
});

return exports;

}());
<commit_msg>Disable compose fading for incomplete/wrong stream names<commit_after>var compose_fade = (function () {

var exports = {};

var focused_recipient;
var normal_display = false;

exports.set_focused_recipient = function (msg_type) {
    if (msg_type === undefined) {
        focused_recipient = undefined;
    }

    // Construct focused_recipient as a mocked up element which has all the
    // fields of a message used by util.same_recipient()
    focused_recipient = {
        type: msg_type
    };

    if (focused_recipient.type === "stream") {
        focused_recipient.stream = $('#stream').val();
        focused_recipient.subject = $('#subject').val();
    } else {
        // Normalize the recipient list so it matches the one used when
        // adding the message (see add_message_metadata(), zulip.js).
        focused_recipient.reply_to = util.normalize_recipients(
                $('#private_message_recipient').val());
    }
};

function _display_messages_normally() {
    rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row")
                                               .removeClass("faded").removeClass("unfaded");

    normal_display = true;
    ui.update_floating_recipient_bar();
}

function _display_users_normally() {
    if (!feature_flags.fade_users_when_composing) {
        return;
    }
    $('.user_sidebar_entry').removeClass('faded').removeClass('unfaded');
}

function _fade_messages() {
    var i;
    var all_elts = rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row");
    var should_fade_message = false;

    normal_display = false;

    // Note: The below algorithm relies on the fact that all_elts is
    // sorted as it would be displayed in the message view
    for (i = 0; i < all_elts.length; i++) {
        var elt = $(all_elts[i]);
        if (elt.hasClass("recipient_row")) {
            should_fade_message = !util.same_recipient(focused_recipient, current_msg_list.get(rows.id(elt)));
        }

        if (should_fade_message) {
            elt.removeClass("unfaded").addClass("faded");
        } else {
            elt.removeClass("faded").addClass("unfaded");
        }
    }

    ui.update_floating_recipient_bar();
}

exports.would_receive_message = function (email) {
    // Given the current focused_recipient, this function returns true if
    // the user in question would definitely receive this message, false if
    // they would definitely not receive this message, and undefined if we
    // don't know (e.g. the recipient is a stream we're not subscribed to).
    //
    // Yes it's slightly weird to have three return values, but this will be
    // helpful if we want to emphasize the '.unfaded' class later (applied
    // to users who will definitely receive the message).

    if (email === page_params.email) {
        // We never want to fade you yourself, so pretend it's true even if
        // it's not.
        return true;
    }

    if (focused_recipient.type === 'stream') {
        return stream_data.user_is_subscribed(focused_recipient.stream, email);
    }

    // PM, so check if the given email is in the recipients list.
    var recipients = focused_recipient.reply_to.split(',');
    return recipients.indexOf(email) !== -1;
};

function _fade_users() {
    if (!feature_flags.fade_users_when_composing) {
        return;
    }
    _.forEach($('.user_sidebar_entry'), function (elt) {
        elt = $(elt);
        var would_receive = exports.would_receive_message(elt.attr('data-email'));
        if (would_receive === true) {
            elt.addClass('unfaded').removeClass('faded');
        } else if (would_receive === false) {
            elt.addClass('faded').removeClass('unfaded');
        } else {
            elt.removeClass('faded').removeClass('unfaded');
        }
    });
}

function _want_normal_display() {
    // If we're not composing show a normal display.
    if (focused_recipient === undefined) {
        return true;
    }

    // If the user really hasn't specified anything let, then we want a normal display
    if (focused_recipient.type === "stream") {
        // If a stream doesn't exist, there is no real chance of a mix, so fading
        // is just noise to the user.
        if (!stream_data.get_sub(focused_recipient.stream)) {
            return true;
        }

        // This is kind of debatable.  If the topic is empty, it could be that
        // the user simply hasn't started typing it yet, but disabling fading here
        // means the feature doesn't help realms where topics aren't mandatory
        // (which is most realms as of this writing).
        if (focused_recipient.subject === "") {
            return true;
        }
    }

    if (focused_recipient.type === "private" && focused_recipient.reply_to === "") {
        return true;
    }

    return false;
}

function _update_faded_messages() {
    // See also update_faded_messages(), which just wraps this with a debounce.
    // FIXME: This fades users too now, as well as messages, so should have
    // a better name.
    if (_want_normal_display()) {
        if (!normal_display) {
            _display_messages_normally();
            _display_users_normally();
        }
    }
    else {
        _fade_messages();
        _fade_users();
    }
}

// This one only updates the users, not both, like update_faded_messages.
// This is for when new presence information comes in, redrawing the presence
// list.
exports.update_faded_users = function () {
    if (_want_normal_display()) {
        _display_users_normally();
    } else {
        _fade_users();
    }
};

// See trac #1633.  For fast typists, calls to _update_faded_messages can
// cause typing sluggishness.
exports.update_faded_messages = _.debounce(_update_faded_messages, 50);

exports.start_compose = function (msg_type) {
    exports.set_focused_recipient(msg_type);
    _update_faded_messages();
};

exports.clear_compose = function () {
    focused_recipient = undefined;
    _display_messages_normally();
    _display_users_normally();
};

exports.update_message_list = function () {
    if (_want_normal_display()) {
       _display_messages_normally();
    }
    else {
        _fade_messages();
    }
};

exports.update_rendered_messages = function (messages, get_elements) {
    if (_want_normal_display()) {
        return;
    }

    // This loop is superficially similar to some code in _fade_messages, but an
    // important difference here is that we look at each message individually, whereas
    // the other code takes advantage of blocks beneath recipient bars.
    //
    // get_elements() is plural, because we can get up to two elements:
    //   the message (always)
    //   the recipient bar (sometimes)
    _.each(messages, function (message) {
        var elts = get_elements(message);
        var should_fade_message = !util.same_recipient(focused_recipient, message);

        _.each(elts, function (elt) {
            if (should_fade_message) {
                elt.removeClass("unfaded").addClass("faded");
            } else {
                elt.removeClass("faded").addClass("unfaded");
            }
        });
    });
};

$(function () {
    $(document).on('peer_subscribe.zulip', function (e) {
        exports.update_faded_users();
    });
    $(document).on('peer_unsubscribe.zulip', function (e) {
        exports.update_faded_users();
    });
});

return exports;

}());
<|endoftext|>


<commit_before>var requirejs = require('requirejs');

var Rewrite = function (from, to) {
    this.$from = from;
    this.$to = to;
};

var config = {
    baseUrl: './public',
    modules: [
        {
            name: 'app/Index',
            create: true,
            include: [
                'inherit',
                'flow',
                'underscore',
                'js/lib/parser',
                'js/plugins/json',
                'js/core/Bus',
                'js/core/Stage',
                'js/core/WindowManager',
                'js/core/HeadManager',
                'js/core/Injection',
                'xaml!app/Index'
            ]
        },
        {
            name: 'app/module/Home',
            create: true,
            include: [
                'xaml!app/module/Home'
            ],
            exclude: [
                'app/Index'
            ]
        }
        ,{
            name: 'app/module/Documentation',
            create: true,
            include: [
                'xaml!app/module/Documentation',
                'js/data/RestDataSource',
                'js/data/FilterDataView',
                'js/data/Model'
            ],
            exclude: [
                'app/Index'
            ]
        },
        {
            name: 'app/module/License',
            create: true,
            include: [
                'xaml!app/module/License'
            ],
            exclude: [
                'app/Index'
            ]
        },
        {
            name: 'app/module/Disclaimer',
            create: true,
            include: [
                'xaml!app/module/Disclaimer'
            ],
            exclude: [
                'app/Index'
            ]
        }
    ],
    dir: 'public-build',
    optimize: 'none',
    nodeRequire: require,
    findNestedDependencies: false,
    optimizeAllPluginResources: true,
    preserveLicenseComments: false,
    //If using UglifyJS for script optimization, these config options can be
    //used to pass configuration values to UglifyJS.
    //See https://github.com/mishoo/UglifyJS for the possible values.
    uglify: {
        toplevel: true,
        ascii_only: true,
        beautify: true,
        except: ['/Users/mkre/dev/git/rappidjs.com/public-build/example/basic/AppClass.js']
    },
    "paths": {
        "text" : 'js/plugins/text',
        "xaml": "js/plugins/xaml",
        "json": "js/plugins/json",
        "raw": "js/plugins/raw",
        "flow": "js/lib/flow",
        "inherit": "js/lib/inherit",
        "underscore": "js/lib/underscore",
        "JSON": "js/lib/JSON"
    },
    onBuildRead: function (moduleName, path, contents) {

        if(moduleName == "app/module/Documentation"){
            console.log(moduleName, contents);
        }
        return contents;
    },
    onBuildWrite: function (moduleName, path, contents) {
        if (moduleName == "inherit") {
            contents = "define('inherit', function () { "+ contents + "; return inherit; });"
        } else if (moduleName == "underscore") {
            contents = "define('underscore', function () { " + contents + "; return _; });"
        } else if (moduleName == "flow") {
            contents = "define('flow', function () { " + contents + "; return flow; });"
        } else if (moduleName == "js/lib/parser") {
            contents = "define('js/lib/parser', function () { "+ contents + "; return this.parser; });"
        } else if (moduleName == "JSON") {
            contents = "define('JSON', function () { " + contents + "; return JSON; });"
        } else if (moduleName == "app/lib/highlight/highlight") {
            contents = "define('app/lib/highlight/highlight', function() { " + contents + "; return hljs; });"
        } else if(moduleName == "app/module/Documentation"){
            console.log(contents);
        }
        return contents;
    },
    skipModuleInsertion: false,
    namespaceMap: {
        "http://www.w3.org/1999/xhtml": "js.html"
    },
    rewriteMap: [
        new Rewrite(/^js\/html\/(a)$/, "js/html/a"),
        new Rewrite(/^js\/html\/(input)$/, "js/html/Input"),
        new Rewrite(/^js\/html\/(select)$/, "js/html/Select"),
        new Rewrite(/^js\/html\/(textarea)$/, "js/html/TextArea"),
        new Rewrite(/^js\/html\/(option)$/, "js/html/Option"),
        new Rewrite(/^js\/html\/(.+)$/, "js/html/HtmlElement")
    ],
    xamlClasses: ["example/basic/App", "example/contact/App", "example/contact/view/Card", "example/todo/App", "js/ui/ButtonGroup", "js/ui/Link", "js/ui/MenuButton", "js/ui/ScrollView", "js/ui/SplitButton", "js/ui/TabView"],

    logLevel: 0
};

global.libxml = require("libxml");

requirejs.optimize(config, function (results) {
    console.log(results);
});
<commit_msg>cleaned up build file<commit_after>var requirejs = require('requirejs');

var Rewrite = function (from, to) {
    this.$from = from;
    this.$to = to;
};

var config = {
    baseUrl: './public',
    modules: [
        {
            name: 'app/Index',
            create: true,
            include: [
                'inherit',
                'flow',
                'underscore',
                'js/lib/parser',
                'js/plugins/json',
                'js/core/Bus',
                'js/core/Stage',
                'js/core/WindowManager',
                'js/core/HeadManager',
                'js/core/Injection',
                'xaml!app/Index'
            ]
        },
        {
            name: 'app/module/Home',
            create: true,
            include: [
                'xaml!app/module/Home'
            ],
            exclude: [
                'app/Index'
            ]
        }
        ,{
            name: 'app/module/Documentation',
            create: true,
            include: [
                'xaml!app/module/Documentation',
                'js/data/RestDataSource',
                'js/data/FilterDataView',
                'js/data/Model'
            ],
            exclude: [
                'app/Index'
            ]
        },
        {
            name: 'app/module/License',
            create: true,
            include: [
                'xaml!app/module/License'
            ],
            exclude: [
                'app/Index'
            ]
        },
        {
            name: 'app/module/Disclaimer',
            create: true,
            include: [
                'xaml!app/module/Disclaimer'
            ],
            exclude: [
                'app/Index'
            ]
        }
    ],
    dir: 'public-build',
    optimize: 'none',
    nodeRequire: require,
    findNestedDependencies: false,
    optimizeAllPluginResources: true,
    preserveLicenseComments: false,
    //If using UglifyJS for script optimization, these config options can be
    //used to pass configuration values to UglifyJS.
    //See https://github.com/mishoo/UglifyJS for the possible values.
    uglify: {
        toplevel: true,
        ascii_only: true,
        beautify: true
    },
    "paths": {
        "text" : 'js/plugins/text',
        "xaml": "js/plugins/xaml",
        "json": "js/plugins/json",
        "raw": "js/plugins/raw",
        "flow": "js/lib/flow",
        "inherit": "js/lib/inherit",
        "underscore": "js/lib/underscore",
        "JSON": "js/lib/JSON"
    },
    onBuildRead: function (moduleName, path, contents) {

        if(moduleName == "app/module/Documentation"){
            console.log(moduleName, contents);
        }
        return contents;
    },
    onBuildWrite: function (moduleName, path, contents) {
        if (moduleName == "inherit") {
            contents = "define('inherit', function () { "+ contents + "; return inherit; });"
        } else if (moduleName == "underscore") {
            contents = "define('underscore', function () { " + contents + "; return _; });"
        } else if (moduleName == "flow") {
            contents = "define('flow', function () { " + contents + "; return flow; });"
        } else if (moduleName == "js/lib/parser") {
            contents = "define('js/lib/parser', function () { "+ contents + "; return this.parser; });"
        } else if (moduleName == "JSON") {
            contents = "define('JSON', function () { " + contents + "; return JSON; });"
        } else if (moduleName == "app/lib/highlight/highlight") {
            contents = "define('app/lib/highlight/highlight', function() { " + contents + "; return hljs; });"
        } else if(moduleName == "app/module/Documentation"){
            console.log(contents);
        }
        return contents;
    },
    skipModuleInsertion: false,
    namespaceMap: {
        "http://www.w3.org/1999/xhtml": "js.html"
    },
    rewriteMap: [
        new Rewrite(/^js\/html\/(a)$/, "js/html/a"),
        new Rewrite(/^js\/html\/(input)$/, "js/html/Input"),
        new Rewrite(/^js\/html\/(select)$/, "js/html/Select"),
        new Rewrite(/^js\/html\/(textarea)$/, "js/html/TextArea"),
        new Rewrite(/^js\/html\/(option)$/, "js/html/Option"),
        new Rewrite(/^js\/html\/(.+)$/, "js/html/HtmlElement")
    ],
    xamlClasses: ["example/basic/App", "example/contact/App", "example/contact/view/Card", "example/todo/App", "js/ui/ButtonGroup", "js/ui/Link", "js/ui/MenuButton", "js/ui/ScrollView", "js/ui/SplitButton", "js/ui/TabView"],

    logLevel: 0
};

global.libxml = require("libxml");

requirejs.optimize(config, function (results) {
    console.log(results);
});
<|endoftext|>


<commit_before>import React from 'react';
import Slider from 'antd/lib/slider';
import {addQuery} from '../../../utils/utils-router';
import 'antd/lib/slider/style/css';

const SliderFilter = props => {
  const {filter, query} = props;

  const queries = attr =>{
    return Object.assign({}, query, {[filter]: attr});
  };

  const checkHealthProp = () => {
    if ('health' in query) return true;
  };

  const marks = {
    0: 0,
    50: {
      style: {
        left: '100%'
      },
      label: 50
    },
  };
console.log(filter);
  return (

{filter} <button className={`btn-pearl btn-padding-small ${checkHealthProp() !== true ? 'display-none' : ''}`}>x</button>

          <Slider range marks={marks} defaultValue={[0, 30]} max={50} onChange={(e)=>addQuery(queries(e))}/>

  );
};

SliderFilter.propTypes = {
  filter: React.PropTypes.string,
  query: React.PropTypes.object
};

export default SliderFilter;<commit_msg>Added button to remove query in slider + styles<commit_after>import React from 'react';
import Slider from 'antd/lib/slider';
import {addQuery, removeQuery} from '../../../utils/utils-router';
import 'antd/lib/slider/style/css';

const SliderFilter = props => {
  const {filter, query} = props;

  const queries = attr =>{
    return Object.assign({}, query, {[filter]: attr});
  };

  const checkHealthProp = () => {
    if ('health' in query) return true;
  };

  const marks = {
    0: 0,
    30: 30,
    50: 50
  };

  return (

{filter} <button onClick={(e)=>removeQuery('health')} className={`btn-pearl btn-padding-small ${checkHealthProp() !== true ? 'display-none' : ''}`}>x</button>

          <Slider range marks={marks} defaultValue={[0, 30]} max={50} onChange={(e)=>addQuery(queries(e))}/>

  );
};

SliderFilter.propTypes = {
  filter: React.PropTypes.string,
  query: React.PropTypes.object
};

export default SliderFilter;<|endoftext|>


<commit_before>$(function() {
    // Register event to show event group forms
    $('#id_event-group-enabled').on('change', function(ev) {
        if (ev.target.checked) {
            $('.event-group').slideDown(200);
        } else {
            $('.event-group').slideUp(200);
        }
    });

    // Register event to show create event group form
    $('.event-group input:radio').on('change', function(ev) {
        var $target = $(ev.target);
        if (ev.target.value==="CRE") {
            $('.event-group-create .panel-body').slideDown(200);
            $('.event-group-create .form-control').prop("disabled", false);
            $('.event-group-select .form-control').prop("disabled", true);
        } else {
            $('.event-group-create .form-control').prop("disabled", true);
            $('.event-group-select .form-control').prop("disabled", false);
        }
    });

    // Initialise datetimepicker's
    $('.js-datetimepicker').datetimepicker({
        format: 'dd/mm/yyyy hh:ii',
        autoclose: true,
    });

    // Set the default end-date to the start date when it is picked
    $('.js-datetimepicker.event-start').datetimepicker().on('changeDate', function(ev){
        $('.js-datetimepicker.event-end').datetimepicker('setDate', ev.date);
    });
});
<commit_msg>Refactor the animationTime<commit_after>var animationTime = 200; // ms

$(function() {
    // Register event to show event group forms
    $('#id_event-group-enabled').on('change', function(ev) {
        if (ev.target.checked) {
            $('.event-group').slideDown(animationTime);
        } else {
            $('.event-group').slideUp(animationTime);
        }
    });

    // Register event to show create event group form
    $('.event-group input:radio').on('change', function(ev) {
        var $target = $(ev.target);
        if (ev.target.value==="CRE") {
            $('.event-group-create .panel-body').slideDown(animationTime);
            $('.event-group-create .form-control').prop("disabled", false);
            $('.event-group-select .form-control').prop("disabled", true);
        } else {
            $('.event-group-create .form-control').prop("disabled", true);
            $('.event-group-select .form-control').prop("disabled", false);
        }
    });

    // Initialise datetimepicker's
    $('.js-datetimepicker').datetimepicker({
        format: 'dd/mm/yyyy hh:ii',
        autoclose: true,
    });

    // Set the default end-date to the start date when it is picked
    $('.js-datetimepicker.event-start').datetimepicker().on('changeDate', function(ev){
        $('.js-datetimepicker.event-end').datetimepicker('setDate', ev.date);
    });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

var program = require('commander'),
    crypto = require('crypto'),
    fs = require('fs'),
    git = require('git-rev'),
    path = require('path'),
    rimraf = require('rimraf'),
    spawn = require('child_process').spawn;

function list(val) {
      return val.split(',');
}

program
    .option('-n, --no-minify', 'Do no minify package')
    .option('-t, --tag [version]', 'Build specific version')
    .option('-m, --modules [module1,module2,...]',
            'Include only these modules in bundle', list)
    .parse(process.argv);

var build = function(tag, cleanup) {
    var filename;
    if (program.modules) {
        // User wants a custom bundle
        var patterns = program.modules.sort().join('&'),
            shasum = crypto.createHash('sha1');
        shasum.update(tag + '?' + patterns);

        var hex = shasum.digest('hex').substr(0,8);
        filename = 'patterns-' + tag+ '-' + hex + (program.minify?'.min':'') + '.js';
    } else {
        filename = 'patterns-' + tag + (program.minify?'.min':'') + '.js';
    }

    var modules = program.modules || ['main'];
    modules = modules.sort();

    // Generate args that are passed to jam
    var fullname = path.join(__dirname, 'bundles', filename);

    // The CLI interface is:
    // jam compile -i pat1 [-i pat2 [-i pat3]] -o outfile
    var args = [ 'compile' ].concat(['--almond', '--verbose', '-i']).
        concat(modules.join(' -i ').split(' ')).concat(['-o', fullname]);

    if (!program.minify)
        args.push('--no-minify');

    var p = spawn(path.join(__dirname, './node_modules/.bin/jam'), args);
    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });
    p.on('exit', function(code) {
        if (code === 0) {
            fs.open(fullname, 'a+', parseInt('0666', 8), function(err, fd){
                if (err) {
                    console.log(err);
                    return cleanup();
                }
                if (modules.indexOf('main') == -1) {
                    var deps = modules
                        .map(function(e){ return '"'+e+'"';  })
                        .join(', ');

                    var code = "require(['registry', " + deps +
                        "], function(r){r.init();});";
                } else {
                    var code = "require(['main']);";
                }
                fs.write(fd, code, null, undefined,
                    function(err, written, buffer){
                        if (err) {
                            console.log(err);
                            return cleanup();
                        }
                        fs.close(fd, function(){
                            var link = path.join(__dirname, 'bundles',
                                'patterns' + (program.minify?'.min':'') + '.js');
                            if (fs.existsSync(link)) {
                                fs.unlinkSync(link);
                            }
                            fs.symlinkSync(filename, link);
                            console.log('Great success!');
                            return cleanup();
                        });
                });
            });
        } else {
            console.log('Build failed ...');
            return cleanup();
        }
    });
    return;
};

var checkout = function(tmpdir, tag) {
    var p = spawn('git', ['checkout', program.tag]);

    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });

    p.on('exit', function(code, status){
        if (code === 0) {
            build(tag, function(){
                rimraf.sync(tmpdir);
                process.exit(0);
            });
        } else {
            console.log('could not checkout tag ' + tag);
            process.exit(1);
        }
    });
};

var clone = function(tmpdir, tag) {
    var p = spawn('git', ['clone', '-s', '.', tmpdir]);

    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });

    p.on('exit', function(code, status){
        if (code === 0) {
            try {
                process.chdir(tmpdir);
            } catch(err) {
                console.log('chdir: ' + err);
                process.exit(1);
            }
            checkout(tmpdir, tag);
        } else {
            console.log('could not clone');
            process.exit(1);
        }
    });

};

if (program.tag) {
    var randChar = function() {
        var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
        return chars[Math.floor(Math.random() * chars.length)];
    };
    var tmpdir;
    do {
        tmpdir = '/tmp/patterns-' + Array(8).join('.').split('').map(randChar).join('');
    } while(fs.existsSync(tmpdir));
    clone(tmpdir, program.tag);
} else {
    git.tag(function (tag) {
        build(tag, function(){});
    });
}

<commit_msg>Add version info to bundles. Fix #258.<commit_after>#!/usr/bin/env node

var program = require('commander'),
    crypto = require('crypto'),
    fs = require('fs'),
    git = require('git-rev'),
    path = require('path'),
    rimraf = require('rimraf'),
    spawn = require('child_process').spawn;

function list(val) {
      return val.split(',');
}

program
    .option('-n, --no-minify', 'Do no minify package')
    .option('-t, --tag [version]', 'Build specific version')
    .option('-m, --modules [module1,module2,...]',
            'Include only these modules in bundle', list)
    .parse(process.argv);

var build = function(tag, cleanup) {
    var filename;
    if (program.modules) {
        // User wants a custom bundle
        var patterns = program.modules.sort().join('&'),
            shasum = crypto.createHash('sha1');
        shasum.update(tag + '?' + patterns);

        var hex = shasum.digest('hex').substr(0,8);
        filename = 'patterns-' + tag+ '-' + hex + (program.minify?'.min':'') + '.js';
    } else {
        filename = 'patterns-' + tag + (program.minify?'.min':'') + '.js';
    }

    var modules = program.modules || ['main'];
    modules = modules.sort();

    // Generate args that are passed to jam
    var fullname = path.join(__dirname, 'bundles', filename);

    // The CLI interface is:
    // jam compile -i pat1 [-i pat2 [-i pat3]] -o outfile
    var args = [ 'compile' ].concat(['--almond', '--verbose', '-i']).
        concat(modules.join(' -i ').split(' ')).concat(['-o', fullname]);

    if (!program.minify)
        args.push('--no-minify');

    var p = spawn(path.join(__dirname, './node_modules/.bin/jam'), args);
    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });
    p.on('exit', function(code) {
        if (code === 0) {
            var header = "/**\n" +
                " * Patterns bundle " + tag + (hex?"-"+hex:"") + "\n" +
                " *\n" +
                " * See http://patternslib.com/ for more information.\n" +
                " *\n";
            console.log(header);
            if (modules.indexOf('main') === -1) {
                header += " * Included patterns:\n * - ";
                header += program.modules.sort().join("\n * - ") + "\n";
            }
            header += " */";

            var js = fs.readFileSync(fullname);

            var init;
            if (modules.indexOf('main') === -1) {
                var deps = modules
                    .map(function(e){ return '"'+e+'"';  })
                    .join(', ');

                init = "require(['registry', " + deps +
                    "], function(r){r.init();});";
            } else {
                init = "require(['main']);";
            }

            var stream = fs.createWriteStream(fullname);
            stream.write(header + js + init);
            stream.end();
            var link = path.join(__dirname, 'bundles',
                'patterns' + (program.minify?'.min':'') + '.js');
            if (fs.existsSync(link)) {
                fs.unlinkSync(link);
            }
            fs.symlinkSync(filename, link);
            console.log('Great success!');
            return cleanup();
        } else {
            console.log('Build failed ...');
            return cleanup();
        }
    });
    return;
};

var checkout = function(tmpdir, tag) {
    var p = spawn('git', ['checkout', program.tag]);

    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });

    p.on('exit', function(code, status){
        if (code === 0) {
            build(tag, function(){
                rimraf.sync(tmpdir);
                process.exit(0);
            });
        } else {
            console.log('could not checkout tag ' + tag);
            process.exit(1);
        }
    });
};

var clone = function(tmpdir, tag) {
    var p = spawn('git', ['clone', '-s', '.', tmpdir]);

    p.stdout.on('data', function(data){
        console.log('stdout ' + data);
    });
    p.stderr.on('data', function(data){
        console.log('stderr ' + data);
    });

    p.on('exit', function(code, status){
        if (code === 0) {
            try {
                process.chdir(tmpdir);
            } catch(err) {
                console.log('chdir: ' + err);
                process.exit(1);
            }
            checkout(tmpdir, tag);
        } else {
            console.log('could not clone');
            process.exit(1);
        }
    });

};

if (program.tag) {
    var randChar = function() {
        var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
        return chars[Math.floor(Math.random() * chars.length)];
    };
    var tmpdir;
    do {
        tmpdir = '/tmp/patterns-' + Array(8).join('.').split('').map(randChar).join('');
    } while(fs.existsSync(tmpdir));
    clone(tmpdir, program.tag);
} else {
    git.tag(function (tag) {
        build(tag, function(){});
    });
}

<|endoftext|>