<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Dictionary of constants (initialized by browser).
 */
var LogEventType = null;
var LogEventPhase = null;
var ClientInfo = null;
var LogSourceType = null;
var NetError = null;
var LoadFlag = null;

/**
 * Object to communicate between the renderer and the browser.
 * @type {!BrowserBridge}
 */
var g_browser = null;

/**
 * Main entry point. called once the page has loaded.
 */
function onLoaded() {
  g_browser = new BrowserBridge();

  // Create the view which displays requests lists, and lets you select, filter
  // and delete them.
  var requestsView = new RequestsView('requestsListTableBody',
                                      'filterInput',
                                      'filterCount',
                                      'deleteSelected',
                                      'selectAll',

                                      // IDs for the details view.
                                      "detailsTabHandles",
                                      "detailsLogTab",
                                      "detailsTimelineTab",
                                      "detailsLogBox",
                                      "detailsTimelineBox",

                                      // IDs for the layout boxes.
                                      "filterBox",
                                      "requestsBox",
                                      "actionBox",
                                      "splitterBox");

  // Create a view which will display info on the proxy setup.
  var proxyView = new ProxyView("proxyTabContent",
                                "proxyCurrentConfig",
                                "proxyReloadSettings",
                                "badProxiesTableBody",
                                "clearBadProxies");

  // Create a view which will display information on the host resolver.
  var dnsView = new DnsView("dnsTabContent",
                            "hostResolverCacheTbody",
                            "clearHostResolverCache",
                            "hostResolverCacheCapacity",
                            "hostResolverCacheTTLSuccess",
                            "hostResolverCacheTTLFailure");

  // Create a view which will display import/export options to control the
  // captured data.
  var dataView = new DataView("dataTabContent", "exportedDataText",
                              "exportToText");

  // Create a view which will display the results and controls for connection
  // tests.
  var testView = new TestView("testTabContent", "testUrlInput",
                              "connectionTestsForm", "testSummary");

  var httpCacheView = new HttpCacheView("httpCacheTabContent",
                                        "httpCacheStats");

  // Create a view which lets you tab between the different sub-views.
  var categoryTabSwitcher =
      new TabSwitcherView(new DivView('categoryTabHandles'));

  // Populate the main tabs.
  categoryTabSwitcher.addTab('requestsTab', requestsView, false);
  categoryTabSwitcher.addTab('proxyTab', proxyView, false);
  categoryTabSwitcher.addTab('dnsTab', dnsView, false);
  categoryTabSwitcher.addTab('socketsTab', new DivView('socketsTabContent'),
                             false);
  categoryTabSwitcher.addTab('httpCacheTab', httpCacheView, false);
  categoryTabSwitcher.addTab('dataTab', dataView, false);
  categoryTabSwitcher.addTab('testTab', testView, false);

  // Build a map from the anchor name of each tab handle to its "tab ID".
  // We will consider navigations to the #hash as a switch tab request.
  var anchorMap = {};
  var tabIds = categoryTabSwitcher.getAllTabIds();
  for (var i = 0; i < tabIds.length; ++i) {
    var aNode = document.getElementById(tabIds[i]);
    anchorMap[aNode.hash] = tabIds[i];
  }
  // Default the empty hash to the requests tab.
  anchorMap['#'] = anchorMap[''] = 'requestsTab';

  window.onhashchange = function() {
    var tabId = anchorMap[window.location.hash];
    if (tabId)
      categoryTabSwitcher.switchToTab(tabId);
  };

  // Make this category tab widget the primary view, that fills the whole page.
  var windowView = new WindowView(categoryTabSwitcher);

  // Trigger initial layout.
  windowView.resetGeometry();

  // Select the initial view based on the current URL.
  window.onhashchange();

  // Tell the browser that we are ready to start receiving log events.
  g_browser.sendReady();
}

/**
 * This class provides a "bridge" for communicating between the javascript and
 * the browser.
 *
 * @constructor
 */
function BrowserBridge() {
  // List of observers for various bits of browser state.
  this.logObservers_ = [];
  this.connectionTestsObservers_ = [];
  this.proxySettings_ = new PollableDataHelper('onProxySettingsChanged');
  this.badProxies_ = new PollableDataHelper('onBadProxiesChanged');
  this.httpCacheInfo_ = new PollableDataHelper('onHttpCacheInfoChanged');
  this.hostResolverCache_ =
      new PollableDataHelper('onHostResolverCacheChanged');

  // Cache of the data received.
  // TODO(eroman): the controls to clear data in the "Requests" tab should be
  //               affecting this as well.
  this.passivelyCapturedEvents_ = [];
  this.activelyCapturedEvents_ = [];
}

/**
 * Delay in milliseconds between polling of certain browser information.
 */
BrowserBridge.POLL_INTERVAL_MS = 5000;

//------------------------------------------------------------------------------
// Messages sent to the browser
//------------------------------------------------------------------------------

BrowserBridge.prototype.sendReady = function() {
  chrome.send('notifyReady');

  // Some of the data we are interested is not currently exposed as a stream,
  // so we will poll the browser to find out when it changes and then notify
  // the observers.
  window.setInterval(
      this.doPolling_.bind(this), BrowserBridge.POLL_INTERVAL_MS);
};

BrowserBridge.prototype.sendGetProxySettings = function() {
  // The browser will call receivedProxySettings on completion.
  chrome.send('getProxySettings');
};

BrowserBridge.prototype.sendReloadProxySettings = function() {
  chrome.send('reloadProxySettings');
};

BrowserBridge.prototype.sendGetBadProxies = function() {
  // The browser will call receivedBadProxies on completion.
  chrome.send('getBadProxies');
};

BrowserBridge.prototype.sendGetHostResolverCache = function() {
  // The browser will call receivedHostResolverCache on completion.
  chrome.send('getHostResolverCache');
};

BrowserBridge.prototype.sendClearBadProxies = function() {
  chrome.send('clearBadProxies');
};

BrowserBridge.prototype.sendClearHostResolverCache = function() {
  chrome.send('clearHostResolverCache');
};

BrowserBridge.prototype.sendStartConnectionTests = function(url) {
  chrome.send('startConnectionTests', [url]);
};

BrowserBridge.prototype.sendGetHttpCacheInfo = function() {
  chrome.send('getHttpCacheInfo');
};

//------------------------------------------------------------------------------
// Messages received from the browser
//------------------------------------------------------------------------------

BrowserBridge.prototype.receivedLogEntry = function(logEntry) {
  if (!logEntry.wasPassivelyCaptured)
    this.activelyCapturedEvents_.push(logEntry);
  for (var i = 0; i < this.logObservers_.length; ++i)
    this.logObservers_[i].onLogEntryAdded(logEntry);
};

BrowserBridge.prototype.receivedLogEventTypeConstants = function(constantsMap) {
  LogEventType = constantsMap;
};

BrowserBridge.prototype.receivedClientInfo =
function(info) {
  ClientInfo = info;
};

BrowserBridge.prototype.receivedLogEventPhaseConstants =
function(constantsMap) {
  LogEventPhase = constantsMap;
};

BrowserBridge.prototype.receivedLogSourceTypeConstants =
function(constantsMap) {
  LogSourceType = constantsMap;
};

BrowserBridge.prototype.receivedLoadFlagConstants = function(constantsMap) {
  LoadFlag = constantsMap;
};

BrowserBridge.prototype.receivedNetErrorConstants = function(constantsMap) {
  NetError = constantsMap;
};

BrowserBridge.prototype.receivedTimeTickOffset = function(timeTickOffset) {
  this.timeTickOffset_ = timeTickOffset;
};

BrowserBridge.prototype.receivedProxySettings = function(proxySettings) {
  this.proxySettings_.update(proxySettings);
};

BrowserBridge.prototype.receivedBadProxies = function(badProxies) {
  this.badProxies_.update(badProxies);
};

BrowserBridge.prototype.receivedHostResolverCache =
function(hostResolverCache) {
  this.hostResolverCache_.update(hostResolverCache);
};

BrowserBridge.prototype.receivedPassiveLogEntries = function(entries) {
  this.passivelyCapturedEvents_ =
      this.passivelyCapturedEvents_.concat(entries);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    entry.wasPassivelyCaptured = true;
    this.receivedLogEntry(entry);
  }
};

BrowserBridge.prototype.receivedStartConnectionTestSuite = function() {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i)
    this.connectionTestsObservers_[i].onStartedConnectionTestSuite();
};

BrowserBridge.prototype.receivedStartConnectionTestExperiment = function(
    experiment) {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i) {
    this.connectionTestsObservers_[i].onStartedConnectionTestExperiment(
        experiment);
  }
};

BrowserBridge.prototype.receivedCompletedConnectionTestExperiment =
function(info) {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i) {
    this.connectionTestsObservers_[i].onCompletedConnectionTestExperiment(
        info.experiment, info.result);
  }
};

BrowserBridge.prototype.receivedCompletedConnectionTestSuite = function() {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i)
    this.connectionTestsObservers_[i].onCompletedConnectionTestSuite();
};

BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
  this.httpCacheInfo_.update(info);
};

//------------------------------------------------------------------------------

/**
 * Adds a listener of log entries. |observer| will be called back when new log
 * data arrives, through:
 *
 *   observer.onLogEntryAdded(logEntry)
 */
BrowserBridge.prototype.addLogObserver = function(observer) {
  this.logObservers_.push(observer);
};

/**
 * Adds a listener of the proxy settings. |observer| will be called back when
 * data is received, through:
 *
 *   observer.onProxySettingsChanged(proxySettings)
 *
 * |proxySettings| is a formatted string describing the settings.
 * TODO(eroman): send a dictionary instead.
 */
BrowserBridge.prototype.addProxySettingsObserver = function(observer) {
  this.proxySettings_.addObserver(observer);
};

/**
 * Adds a listener of the proxy settings. |observer| will be called back when
 * data is received, through:
 *
 *   observer.onBadProxiesChanged(badProxies)
 *
 * |badProxies| is an array, where each entry has the property:
 *   badProxies[i].proxy_uri: String identify the proxy.
 *   badProxies[i].bad_until: The time when the proxy stops being considered
 *                            bad. Note the time is in time ticks.
 */
BrowserBridge.prototype.addBadProxiesObsever = function(observer) {
  this.badProxies_.addObserver(observer);
};

/**
 * Adds a listener of the host resolver cache. |observer| will be called back
 * when data is received, through:
 *
 *   observer.onHostResolverCacheChanged(hostResolverCache)
 */
BrowserBridge.prototype.addHostResolverCacheObserver = function(observer) {
  this.hostResolverCache_.addObserver(observer);
};

/**
 * Adds a listener for the progress of the connection tests.
 * The observer will be called back with:
 *
 *   observer.onStartedConnectionTestSuite();
 *   observer.onStartedConnectionTestExperiment(experiment);
 *   observer.onCompletedConnectionTestExperiment(experiment, result);
 *   observer.onCompletedConnectionTestSuite();
 */
BrowserBridge.prototype.addConnectionTestsObserver = function(observer) {
  this.connectionTestsObservers_.push(observer);
};

/**
 * Adds a listener for the http cache info results.
 * The observer will be called back with:
 *
 *   observer.onHttpCacheInfoChanged(info);
 */
BrowserBridge.prototype.addHttpCacheInfoObserver = function(observer) {
  this.httpCacheInfo_.addObserver(observer);
};

/**
 * The browser gives us times in terms of "time ticks" in milliseconds.
 * This function converts the tick count to a Date() object.
 *
 * @param {String} timeTicks.
 * @returns {Date} The time that |timeTicks| represents.
 */
BrowserBridge.prototype.convertTimeTicksToDate = function(timeTicks) {
  // Note that the subtraction by 0 is to cast to a number (probably a float
  // since the numbers are big).
  var timeStampMs = (this.timeTickOffset_ - 0) + (timeTicks - 0);
  var d = new Date();
  d.setTime(timeStampMs);
  return d;
};

/**
 * Returns a list of all the events that were captured while we were
 * listening for events.
 */
BrowserBridge.prototype.getAllActivelyCapturedEvents = function() {
  return this.activelyCapturedEvents_;
};

/**
 * Returns a list of all the events that were captured passively by the
 * browser prior to when the net-internals page was started.
 */
BrowserBridge.prototype.getAllPassivelyCapturedEvents = function() {
  return this.passivelyCapturedEvents_;
};

BrowserBridge.prototype.doPolling_ = function() {
  // TODO(eroman): Optimize this by using a separate polling frequency for the
  // data consumed by the currently active view. Everything else can be on a low
  // frequency poll since it won't impact the display.
  this.sendGetProxySettings();
  this.sendGetBadProxies();
  this.sendGetHostResolverCache();
  this.sendGetHttpCacheInfo();
};

/**
 * This is a helper class used by BrowserBridge, to keep track of:
 *   - the list of observers interested in some piece of data.
 *   - the last known value of that piece of data.
 *   - the name of the callback method to invoke on observers.
 * @constructor
 */
function PollableDataHelper(observerMethodName) {
  this.observerMethodName_ = observerMethodName;
  this.observers_ = [];
}

PollableDataHelper.prototype.addObserver = function(observer) {
  this.observers_.push(observer);
};

/**
 * Helper function to handle calling all the observers, but ONLY if the data has
 * actually changed since last time. This is used for data we received from
 * browser on a poll loop.
 */
PollableDataHelper.prototype.update = function(data) {
  var prevData = this.currentData_;

  // If the data hasn't changed since last time, no need to notify observers.
  if (prevData && JSON.stringify(prevData) == JSON.stringify(data))
    return;

  this.currentData_ = data;

  // Ok, notify the observers of the change.
  for (var i = 0; i < this.observers_.length; ++i)
    var observer = this.observers_[i];
    observer[this.observerMethodName_](data);
};
<commit_msg>Change the default tab on net-internals from "requests" to "data".<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Dictionary of constants (initialized by browser).
 */
var LogEventType = null;
var LogEventPhase = null;
var ClientInfo = null;
var LogSourceType = null;
var NetError = null;
var LoadFlag = null;

/**
 * Object to communicate between the renderer and the browser.
 * @type {!BrowserBridge}
 */
var g_browser = null;

/**
 * Main entry point. called once the page has loaded.
 */
function onLoaded() {
  g_browser = new BrowserBridge();

  // Create the view which displays requests lists, and lets you select, filter
  // and delete them.
  var requestsView = new RequestsView('requestsListTableBody',
                                      'filterInput',
                                      'filterCount',
                                      'deleteSelected',
                                      'selectAll',

                                      // IDs for the details view.
                                      "detailsTabHandles",
                                      "detailsLogTab",
                                      "detailsTimelineTab",
                                      "detailsLogBox",
                                      "detailsTimelineBox",

                                      // IDs for the layout boxes.
                                      "filterBox",
                                      "requestsBox",
                                      "actionBox",
                                      "splitterBox");

  // Create a view which will display info on the proxy setup.
  var proxyView = new ProxyView("proxyTabContent",
                                "proxyCurrentConfig",
                                "proxyReloadSettings",
                                "badProxiesTableBody",
                                "clearBadProxies");

  // Create a view which will display information on the host resolver.
  var dnsView = new DnsView("dnsTabContent",
                            "hostResolverCacheTbody",
                            "clearHostResolverCache",
                            "hostResolverCacheCapacity",
                            "hostResolverCacheTTLSuccess",
                            "hostResolverCacheTTLFailure");

  // Create a view which will display import/export options to control the
  // captured data.
  var dataView = new DataView("dataTabContent", "exportedDataText",
                              "exportToText");

  // Create a view which will display the results and controls for connection
  // tests.
  var testView = new TestView("testTabContent", "testUrlInput",
                              "connectionTestsForm", "testSummary");

  var httpCacheView = new HttpCacheView("httpCacheTabContent",
                                        "httpCacheStats");

  // Create a view which lets you tab between the different sub-views.
  var categoryTabSwitcher =
      new TabSwitcherView(new DivView('categoryTabHandles'));

  // Populate the main tabs.
  categoryTabSwitcher.addTab('requestsTab', requestsView, false);
  categoryTabSwitcher.addTab('proxyTab', proxyView, false);
  categoryTabSwitcher.addTab('dnsTab', dnsView, false);
  categoryTabSwitcher.addTab('socketsTab', new DivView('socketsTabContent'),
                             false);
  categoryTabSwitcher.addTab('httpCacheTab', httpCacheView, false);
  categoryTabSwitcher.addTab('dataTab', dataView, false);
  categoryTabSwitcher.addTab('testTab', testView, false);

  // Build a map from the anchor name of each tab handle to its "tab ID".
  // We will consider navigations to the #hash as a switch tab request.
  var anchorMap = {};
  var tabIds = categoryTabSwitcher.getAllTabIds();
  for (var i = 0; i < tabIds.length; ++i) {
    var aNode = document.getElementById(tabIds[i]);
    anchorMap[aNode.hash] = tabIds[i];
  }
  // Default the empty hash to the data tab.
  anchorMap['#'] = anchorMap[''] = 'dataTab';

  window.onhashchange = function() {
    var tabId = anchorMap[window.location.hash];
    if (tabId)
      categoryTabSwitcher.switchToTab(tabId);
  };

  // Make this category tab widget the primary view, that fills the whole page.
  var windowView = new WindowView(categoryTabSwitcher);

  // Trigger initial layout.
  windowView.resetGeometry();

  // Select the initial view based on the current URL.
  window.onhashchange();

  // Tell the browser that we are ready to start receiving log events.
  g_browser.sendReady();
}

/**
 * This class provides a "bridge" for communicating between the javascript and
 * the browser.
 *
 * @constructor
 */
function BrowserBridge() {
  // List of observers for various bits of browser state.
  this.logObservers_ = [];
  this.connectionTestsObservers_ = [];
  this.proxySettings_ = new PollableDataHelper('onProxySettingsChanged');
  this.badProxies_ = new PollableDataHelper('onBadProxiesChanged');
  this.httpCacheInfo_ = new PollableDataHelper('onHttpCacheInfoChanged');
  this.hostResolverCache_ =
      new PollableDataHelper('onHostResolverCacheChanged');

  // Cache of the data received.
  // TODO(eroman): the controls to clear data in the "Requests" tab should be
  //               affecting this as well.
  this.passivelyCapturedEvents_ = [];
  this.activelyCapturedEvents_ = [];
}

/**
 * Delay in milliseconds between polling of certain browser information.
 */
BrowserBridge.POLL_INTERVAL_MS = 5000;

//------------------------------------------------------------------------------
// Messages sent to the browser
//------------------------------------------------------------------------------

BrowserBridge.prototype.sendReady = function() {
  chrome.send('notifyReady');

  // Some of the data we are interested is not currently exposed as a stream,
  // so we will poll the browser to find out when it changes and then notify
  // the observers.
  window.setInterval(
      this.doPolling_.bind(this), BrowserBridge.POLL_INTERVAL_MS);
};

BrowserBridge.prototype.sendGetProxySettings = function() {
  // The browser will call receivedProxySettings on completion.
  chrome.send('getProxySettings');
};

BrowserBridge.prototype.sendReloadProxySettings = function() {
  chrome.send('reloadProxySettings');
};

BrowserBridge.prototype.sendGetBadProxies = function() {
  // The browser will call receivedBadProxies on completion.
  chrome.send('getBadProxies');
};

BrowserBridge.prototype.sendGetHostResolverCache = function() {
  // The browser will call receivedHostResolverCache on completion.
  chrome.send('getHostResolverCache');
};

BrowserBridge.prototype.sendClearBadProxies = function() {
  chrome.send('clearBadProxies');
};

BrowserBridge.prototype.sendClearHostResolverCache = function() {
  chrome.send('clearHostResolverCache');
};

BrowserBridge.prototype.sendStartConnectionTests = function(url) {
  chrome.send('startConnectionTests', [url]);
};

BrowserBridge.prototype.sendGetHttpCacheInfo = function() {
  chrome.send('getHttpCacheInfo');
};

//------------------------------------------------------------------------------
// Messages received from the browser
//------------------------------------------------------------------------------

BrowserBridge.prototype.receivedLogEntry = function(logEntry) {
  if (!logEntry.wasPassivelyCaptured)
    this.activelyCapturedEvents_.push(logEntry);
  for (var i = 0; i < this.logObservers_.length; ++i)
    this.logObservers_[i].onLogEntryAdded(logEntry);
};

BrowserBridge.prototype.receivedLogEventTypeConstants = function(constantsMap) {
  LogEventType = constantsMap;
};

BrowserBridge.prototype.receivedClientInfo =
function(info) {
  ClientInfo = info;
};

BrowserBridge.prototype.receivedLogEventPhaseConstants =
function(constantsMap) {
  LogEventPhase = constantsMap;
};

BrowserBridge.prototype.receivedLogSourceTypeConstants =
function(constantsMap) {
  LogSourceType = constantsMap;
};

BrowserBridge.prototype.receivedLoadFlagConstants = function(constantsMap) {
  LoadFlag = constantsMap;
};

BrowserBridge.prototype.receivedNetErrorConstants = function(constantsMap) {
  NetError = constantsMap;
};

BrowserBridge.prototype.receivedTimeTickOffset = function(timeTickOffset) {
  this.timeTickOffset_ = timeTickOffset;
};

BrowserBridge.prototype.receivedProxySettings = function(proxySettings) {
  this.proxySettings_.update(proxySettings);
};

BrowserBridge.prototype.receivedBadProxies = function(badProxies) {
  this.badProxies_.update(badProxies);
};

BrowserBridge.prototype.receivedHostResolverCache =
function(hostResolverCache) {
  this.hostResolverCache_.update(hostResolverCache);
};

BrowserBridge.prototype.receivedPassiveLogEntries = function(entries) {
  this.passivelyCapturedEvents_ =
      this.passivelyCapturedEvents_.concat(entries);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    entry.wasPassivelyCaptured = true;
    this.receivedLogEntry(entry);
  }
};

BrowserBridge.prototype.receivedStartConnectionTestSuite = function() {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i)
    this.connectionTestsObservers_[i].onStartedConnectionTestSuite();
};

BrowserBridge.prototype.receivedStartConnectionTestExperiment = function(
    experiment) {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i) {
    this.connectionTestsObservers_[i].onStartedConnectionTestExperiment(
        experiment);
  }
};

BrowserBridge.prototype.receivedCompletedConnectionTestExperiment =
function(info) {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i) {
    this.connectionTestsObservers_[i].onCompletedConnectionTestExperiment(
        info.experiment, info.result);
  }
};

BrowserBridge.prototype.receivedCompletedConnectionTestSuite = function() {
  for (var i = 0; i < this.connectionTestsObservers_.length; ++i)
    this.connectionTestsObservers_[i].onCompletedConnectionTestSuite();
};

BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
  this.httpCacheInfo_.update(info);
};

//------------------------------------------------------------------------------

/**
 * Adds a listener of log entries. |observer| will be called back when new log
 * data arrives, through:
 *
 *   observer.onLogEntryAdded(logEntry)
 */
BrowserBridge.prototype.addLogObserver = function(observer) {
  this.logObservers_.push(observer);
};

/**
 * Adds a listener of the proxy settings. |observer| will be called back when
 * data is received, through:
 *
 *   observer.onProxySettingsChanged(proxySettings)
 *
 * |proxySettings| is a formatted string describing the settings.
 * TODO(eroman): send a dictionary instead.
 */
BrowserBridge.prototype.addProxySettingsObserver = function(observer) {
  this.proxySettings_.addObserver(observer);
};

/**
 * Adds a listener of the proxy settings. |observer| will be called back when
 * data is received, through:
 *
 *   observer.onBadProxiesChanged(badProxies)
 *
 * |badProxies| is an array, where each entry has the property:
 *   badProxies[i].proxy_uri: String identify the proxy.
 *   badProxies[i].bad_until: The time when the proxy stops being considered
 *                            bad. Note the time is in time ticks.
 */
BrowserBridge.prototype.addBadProxiesObsever = function(observer) {
  this.badProxies_.addObserver(observer);
};

/**
 * Adds a listener of the host resolver cache. |observer| will be called back
 * when data is received, through:
 *
 *   observer.onHostResolverCacheChanged(hostResolverCache)
 */
BrowserBridge.prototype.addHostResolverCacheObserver = function(observer) {
  this.hostResolverCache_.addObserver(observer);
};

/**
 * Adds a listener for the progress of the connection tests.
 * The observer will be called back with:
 *
 *   observer.onStartedConnectionTestSuite();
 *   observer.onStartedConnectionTestExperiment(experiment);
 *   observer.onCompletedConnectionTestExperiment(experiment, result);
 *   observer.onCompletedConnectionTestSuite();
 */
BrowserBridge.prototype.addConnectionTestsObserver = function(observer) {
  this.connectionTestsObservers_.push(observer);
};

/**
 * Adds a listener for the http cache info results.
 * The observer will be called back with:
 *
 *   observer.onHttpCacheInfoChanged(info);
 */
BrowserBridge.prototype.addHttpCacheInfoObserver = function(observer) {
  this.httpCacheInfo_.addObserver(observer);
};

/**
 * The browser gives us times in terms of "time ticks" in milliseconds.
 * This function converts the tick count to a Date() object.
 *
 * @param {String} timeTicks.
 * @returns {Date} The time that |timeTicks| represents.
 */
BrowserBridge.prototype.convertTimeTicksToDate = function(timeTicks) {
  // Note that the subtraction by 0 is to cast to a number (probably a float
  // since the numbers are big).
  var timeStampMs = (this.timeTickOffset_ - 0) + (timeTicks - 0);
  var d = new Date();
  d.setTime(timeStampMs);
  return d;
};

/**
 * Returns a list of all the events that were captured while we were
 * listening for events.
 */
BrowserBridge.prototype.getAllActivelyCapturedEvents = function() {
  return this.activelyCapturedEvents_;
};

/**
 * Returns a list of all the events that were captured passively by the
 * browser prior to when the net-internals page was started.
 */
BrowserBridge.prototype.getAllPassivelyCapturedEvents = function() {
  return this.passivelyCapturedEvents_;
};

BrowserBridge.prototype.doPolling_ = function() {
  // TODO(eroman): Optimize this by using a separate polling frequency for the
  // data consumed by the currently active view. Everything else can be on a low
  // frequency poll since it won't impact the display.
  this.sendGetProxySettings();
  this.sendGetBadProxies();
  this.sendGetHostResolverCache();
  this.sendGetHttpCacheInfo();
};

/**
 * This is a helper class used by BrowserBridge, to keep track of:
 *   - the list of observers interested in some piece of data.
 *   - the last known value of that piece of data.
 *   - the name of the callback method to invoke on observers.
 * @constructor
 */
function PollableDataHelper(observerMethodName) {
  this.observerMethodName_ = observerMethodName;
  this.observers_ = [];
}

PollableDataHelper.prototype.addObserver = function(observer) {
  this.observers_.push(observer);
};

/**
 * Helper function to handle calling all the observers, but ONLY if the data has
 * actually changed since last time. This is used for data we received from
 * browser on a poll loop.
 */
PollableDataHelper.prototype.update = function(data) {
  var prevData = this.currentData_;

  // If the data hasn't changed since last time, no need to notify observers.
  if (prevData && JSON.stringify(prevData) == JSON.stringify(data))
    return;

  this.currentData_ = data;

  // Ok, notify the observers of the change.
  for (var i = 0; i < this.observers_.length; ++i)
    var observer = this.observers_[i];
    observer[this.observerMethodName_](data);
};
<|endoftext|>


<commit_before>var Promise    = require('bluebird');
var rekt       = require('rekt').rekt;
var Book       = requireLocal('models/book.js');
var Page       = requireLocal('models/page.js');
var Difference = requireLocal('models/difference.js');
var _          = require('lodash');
var verifyWord = requireLocal('utils/compare.js');

/** @type {INT} The number of passes before we reject the request. */
var PASSCOUNT = 8;
function updateDifferences(unfilteredDifferences) {

  console.log(unfilteredDifferences);

  // nine passes MAX
  // Seperate passes
  // discard the passes

  // verify the rest,
  // Field is fine but the default should be not pass.
  // remerge passes and write to db

  var uniqueDiffs = _.uniq(unfilteredDifferences, '_id');
  console.log(uniqueDiffs);
  var filteredDiffs = _.map(unfilteredDifferences, verifyWord);
  return Promise.settle(filteredDiffs)
    .then(function(results) {
      var passCount = 0;
      _.forEach(unfilteredDifferences, function(diff) {
        if (diff.pass === true) {
          passCount++;
        }
      });

      if (passCount > PASSCOUNT) {
        console.log('Too many passes');
        throw new rekt.BadRequest('Too many passes');
      }

      if (unfilteredDifferences === 0) {
        throw new rekt.BadRequest('You must provide diffs');
      }
      var possibleDifferences = _.chain(results)
        .map(function(result) {
          if (result.isFulfilled() && result.value) {
            return result.value();
          } else {
            return false;
          }
        })
        .compact()
        .value();
      if (possibleDifferences.length < 1) {
        throw new rekt.BadRequest('All words possible spam.');
      }

      return possibleDifferences;

    })
    .each(function(possible) {
      return Difference.findByIdAsync(possible._id)
        .then(function(foundDifference) {
          if (!foundDifference) {
            throw new rekt.NotFound('Difference not found');
          } else {
            return foundDifference;
          }
        });
    })

  // /**
  //  * Run our verifying algorithm on the unfilteredDifferences provided to us
  //  * by the user.
  //  */
  // var filtedDiffs = _.map(unfilteredDifferences, verifyWord);

  // /**
  //  * Because the verifyWord function is Async we have to wait for all of them
  //  * to either reject or verify. Once they all finish processing we can act on
  //  * them.
  //  */
  // return Promise.settle(filtedDiffs)
  //   .then(function(results) {
  //     var possibleDifferences = _.chain(results)
  //       .map(function(result) {
  //         if (result.isFulfilled() && result.value) {
  //           return result.value();
  //         } else {
  //           return false;
  //         }
  //       })
  //       .compact()
  //       .value();

  //     if (possibleDifferences.length < 1) {
  //       throw new rekt.BadWord('All words possible spam.');
  //     }

  //     return possibleDifferences;

  //   })
  //   .each(function(possibleDifference) {
  //     return Difference.findByIdAsync(possibleDifference._id)
  //       .then(function(foundDifference) {
  //         if (!foundDifference) {
  //           throw new rekt.NotFound('Difference not found');
  //         } else {
  //           return foundDifference;
  //         }
  //       })
  //       .then(function(foundDifference) {
  //         // If the possibleDifference is marked as passible and the max
  //         var index = _.findIndex(foundDifference.tags, {
  //           text: possibleDifference.text
  //         });
  //         if (index > -1) {
  //           var oldWeight = foundDifference.tags[index].weight;
  //           var newWeight = foundDifference.tags[index].weight + 1;
  //           foundDifference.tags.set(index, {
  //             text: possibleDifference.text,
  //             weight: newWeight
  //           });
  //           return foundDifference.saveAsync();
  //         } else {
  //           foundDifference.tags.push({
  //             text: possibleDifference.text,
  //             weight: 0
  //           });
  //           return foundDifference.saveAsync();
  //         }
  //       });
  //   });
}

module.exports = function(router) {
  router.route('/difference')
    .put(function(req, res) {
      var differences = req.body.differences;
      updateDifferences(differences)
        .then(function() {
          res.status(201);
          res.json({
            message: 'Differences updated'
          });
        })
        .catch(function(err) {
          console.log(err);
          res.send(err);
        });
    });
};
<commit_msg>testing diffs<commit_after>var Promise    = require('bluebird');
var rekt       = require('rekt').rekt;
var Book       = requireLocal('models/book.js');
var Page       = requireLocal('models/page.js');
var Difference = requireLocal('models/difference.js');
var _          = require('lodash');
var verifyWord = requireLocal('utils/compare.js');

/** @type {INT} The number of passes before we reject the request. */
var PASSCOUNT = 8;
function updateDifferences(unfilteredDifferences) {

  // nine passes MAX
  // Seperate passes
  // discard the passes

  // verify the rest,
  // Field is fine but the default should be not pass.
  // remerge passes and write to db

  var uniqueDiffs = _.uniq(unfilteredDifferences, '_id');
  console.log(uniqueDiffs);
  var filteredDiffs = _.map(unfilteredDifferences, verifyWord);
  return Promise.settle(filteredDiffs)
    .then(function(results) {
      var passCount = 0;
      _.forEach(unfilteredDifferences, function(diff) {
        if (diff.pass === true) {
          passCount++;
        }
      });

      if (passCount > PASSCOUNT) {
        console.log('Too many passes');
        throw new rekt.BadRequest('Too many passes');
      }

      if (unfilteredDifferences === 0) {
        throw new rekt.BadRequest('You must provide diffs');
      }
      var possibleDifferences = _.chain(results)
        .map(function(result) {
          if (result.isFulfilled() && result.value) {
            return result.value();
          } else {
            return false;
          }
        })
        .compact()
        .value();
      if (possibleDifferences.length < 1) {
        throw new rekt.BadRequest('All words possible spam.');
      }

      return possibleDifferences;

    })
    .each(function(possible) {
      return Difference.findByIdAsync(possible._id)
        .then(function(foundDifference) {
          if (!foundDifference) {
            throw new rekt.NotFound('Difference not found');
          } else {
            return foundDifference;
          }
        });
    })

  // /**
  //  * Run our verifying algorithm on the unfilteredDifferences provided to us
  //  * by the user.
  //  */
  // var filtedDiffs = _.map(unfilteredDifferences, verifyWord);

  // /**
  //  * Because the verifyWord function is Async we have to wait for all of them
  //  * to either reject or verify. Once they all finish processing we can act on
  //  * them.
  //  */
  // return Promise.settle(filtedDiffs)
  //   .then(function(results) {
  //     var possibleDifferences = _.chain(results)
  //       .map(function(result) {
  //         if (result.isFulfilled() && result.value) {
  //           return result.value();
  //         } else {
  //           return false;
  //         }
  //       })
  //       .compact()
  //       .value();

  //     if (possibleDifferences.length < 1) {
  //       throw new rekt.BadWord('All words possible spam.');
  //     }

  //     return possibleDifferences;

  //   })
  //   .each(function(possibleDifference) {
  //     return Difference.findByIdAsync(possibleDifference._id)
  //       .then(function(foundDifference) {
  //         if (!foundDifference) {
  //           throw new rekt.NotFound('Difference not found');
  //         } else {
  //           return foundDifference;
  //         }
  //       })
  //       .then(function(foundDifference) {
  //         // If the possibleDifference is marked as passible and the max
  //         var index = _.findIndex(foundDifference.tags, {
  //           text: possibleDifference.text
  //         });
  //         if (index > -1) {
  //           var oldWeight = foundDifference.tags[index].weight;
  //           var newWeight = foundDifference.tags[index].weight + 1;
  //           foundDifference.tags.set(index, {
  //             text: possibleDifference.text,
  //             weight: newWeight
  //           });
  //           return foundDifference.saveAsync();
  //         } else {
  //           foundDifference.tags.push({
  //             text: possibleDifference.text,
  //             weight: 0
  //           });
  //           return foundDifference.saveAsync();
  //         }
  //       });
  //   });
}

module.exports = function(router) {
  router.route('/difference')
    .put(function(req, res) {
      var differences = req.body.differences;
      updateDifferences(differences)
        .then(function() {
          res.status(201);
          res.json({
            message: 'Differences updated'
          });
        })
        .catch(function(err) {
          console.log(err);
          res.send(err);
        });
    });
};
<|endoftext|>


<commit_before>const route = (app, request, cheerio) => {
  app.get('/goldenbet', (req, res, next) => {
    request.get('https://goldenbet.com/en/', (err, response, body) => {
      if (err) {
        next(Object.assign(err, { status: 502 }));
      }

      const $ = cheerio.load(body);
      const games = $('.uk-table').children('tbody').find('tr');
      const results = [];

      games.each((index, element) => {
        const children = $(element).children('td');
        const equipe_domicile = children.eq(1).text().trim();

        if (children.length > 0 && equipe_domicile != '') {
          results.push({
              equipe_domicile,
              equipe_exterieur: children.eq(2).text().trim(),
              domicile: children.eq(4).text().trim(),
              nul: children.eq(5).text().trim(),
              exterieur: children.eq(6).text().trim()
          });
        }
      });

      res.send({ results });
    });
  });

  return app;
};

module.exports = route;
<commit_msg>fix(goldenbet)<commit_after>const route = (app, request, cheerio) => {
  app.get('/goldenbet', (req, res, next) => {
    request.get('https://goldenbet.com/en/', (err, response, body) => {
      if (err) {
        next(Object.assign(err, { status: 502 }));
      }

      const $ = cheerio.load(body);
      const games = $('.uk-table').children('tbody').find('tr');
      const results = [];

      games.each((index, element) => {
        const children = $(element).children('td');
        const equipe_domicile = children.eq(1).text().trim();

        if (children.length > 0 && equipe_domicile != '') {
          results.push({
              equipe_domicile,
              equipe_exterieur: children.eq(2).text().trim(),
              prediction: children.eq(3).find('.uk-badge').text().trim(),
          });
        }
      });

      res.send({ results });
    });
  });

  return app;
};

module.exports = route;
<|endoftext|>


<commit_before>var RTEI = RTEI || {}
RTEI.country = (function() {

  return {

    currentIndex: null,

    showIndicators(code) {
      var isTheme = (code.substring(0, 1) == 't');
      if (code != RTEI.country.currentIndex) {
        RTEI.country.currentIndex = code;

        if (!isTheme) {
          if ($('#indicators').is(':hidden')) {
            $('#indicators').show();
          }
          if ($('#theme_indicators').is(':visible')) {
            $('#theme_indicators').hide();
          }

          if (code == 'index') {
            // Show all sections, collapsed
            for (var i = 1; i <= 5; i++) {
              if ($('#indicator_container_' + i).is(':hidden')) {
                $('#indicator_container_' + i).show();
              }
              if ($('#indicator_container_' + i).hasClass('open')) {
                $('#indicator_item_' + i).click();
              }
            }
          } else {
            // Hide other sections
            for (var i = 1; i <= 5; i++) {
              if (String(i) !== code) {
                $('#indicator_container_' + i).hide();
              }
            }
            // Expand relevant section
            if ($('#indicator_container_' + code).is(':hidden')) {
              $('#indicator_container_' + code).show();
            }
            if (!$('#indicator_container_' + code).hasClass('open')) {
              $('#indicator_item_' + code).click();
            }
          }
        } else {
          if ($('#theme_indicators').is(':hidden')) {
            $('#theme_indicators').show();
          }
          if ($('#indicators').is(':visible')) {
            $('#indicators').hide();
          }
          // Show the relevant theme indicators list
          $.each($('.theme-indicators'), function(index, ol) {
            if (ol.id.replace('theme_indicators_', '') != code.replace('t', '')) {
              $(ol).hide();
            } else {
              $(ol).slideToggle();
            }
          });
        }
      }
    },

    initChart: function(data) {
      var chart;
      var json_data;
      var chart = c3.generate({
          bindto: '#chart',
          data: {
              json: data,
              order: null,
              keys: {
                  x: 'name',
                  value: ['1', '3', '2', '5', '4']
              },
              groups: [
                  ['1', '2', '3', '4', '5']
              ],
              names: {
                  '1': 'Governance',
                  '3': 'Accessibility',
                  '2': 'Availability',
                  '5': 'Adaptability',
                  '4': 'Acceptability'
              },
              type: 'bar',
              colors: {
                1: '#c35727',
                2: '#bdb831',
                3: '#af1f2c',
                4: '#357b9e',
                5: '#469a8f',
              },
          },
          axis: {
              rotated: true,
              x: {
                  type: 'category',
                  show: false,
              },
              y: {
                  show: true,
                  max: 100,
                  padding: {
                      top: 10,
                      bottom: 10,
                  }
              }
          },
          bar: {
              width: 16
          },
          tooltip: {
            format: {
              value: function (value, ratio, id, index) {
                  return parseFloat((value * 5).toFixed(2));
              }
            }
          },
          padding: {
            bottom: 20,
            left: 5
          }
      });
    }
  }

})();

$(document).ready(function(){

    // Set up country selector
    $('#available-countries').on('change', function(){
      if (this.value) {
        window.location = '/explore/rtei-country?id=' + this.value;
      }
    });

    // If data available, build the chart
    var chartData = $("#chart").data("chart-data");
    if (chartData) {
      RTEI.country.initChart(chartData);
    }

    // Menu switcher
    $('.indicator-switcher input').on('click', function(){
      RTEI.country.showIndicators(this.value);
    });

    // indicators
    $("#indicators ul").slideUp().parent().addClass("has-children");
    $('#indicators .indicator').click(function(e){
      $(this).parent().children('ul').not(':animated').slideToggle().parent().toggleClass("open");
    });

});
<commit_msg>Fix theme indicators sliding down<commit_after>var RTEI = RTEI || {}
RTEI.country = (function() {

  return {

    currentIndex: null,

    showIndicators(code) {
      var isTheme = (code.substring(0, 1) == 't');
      if (code != RTEI.country.currentIndex) {
        RTEI.country.currentIndex = code;

        if (!isTheme) {
          if ($('#indicators').is(':hidden')) {
            $('#indicators').show();
          }
          if ($('#theme_indicators').is(':visible')) {
            $('#theme_indicators').hide();
          }

          if (code == 'index') {
            // Show all sections, collapsed
            for (var i = 1; i <= 5; i++) {
              if ($('#indicator_container_' + i).is(':hidden')) {
                $('#indicator_container_' + i).show();
              }
              if ($('#indicator_container_' + i).hasClass('open')) {
                $('#indicator_item_' + i).click();
              }
            }
          } else {
            // Hide other sections
            for (var i = 1; i <= 5; i++) {
              if (String(i) !== code) {
                $('#indicator_container_' + i).hide();
              }
            }
            // Expand relevant section
            if ($('#indicator_container_' + code).is(':hidden')) {
              $('#indicator_container_' + code).show();
            }
            if (!$('#indicator_container_' + code).hasClass('open')) {
              $('#indicator_item_' + code).click();
            }
          }
        } else {
          if ($('#theme_indicators').is(':hidden')) {
            $('#theme_indicators').show();
          }
          if ($('#indicators').is(':visible')) {
            $('#indicators').hide();
          }
          // Show the relevant theme indicators list
          $.each($('.theme-indicators'), function(index, ol) {
            if (ol.id.replace('theme_indicators_', '') != code.replace('t', '')) {
              $(ol).hide();
            } else {
              $(ol).slideDown();
            }
          });
        }
      }
    },

    initChart: function(data) {
      var chart;
      var json_data;
      var chart = c3.generate({
          bindto: '#chart',
          data: {
              json: data,
              order: null,
              keys: {
                  x: 'name',
                  value: ['1', '3', '2', '5', '4']
              },
              groups: [
                  ['1', '2', '3', '4', '5']
              ],
              names: {
                  '1': 'Governance',
                  '3': 'Accessibility',
                  '2': 'Availability',
                  '5': 'Adaptability',
                  '4': 'Acceptability'
              },
              type: 'bar',
              colors: {
                1: '#c35727',
                2: '#bdb831',
                3: '#af1f2c',
                4: '#357b9e',
                5: '#469a8f',
              },
          },
          axis: {
              rotated: true,
              x: {
                  type: 'category',
                  show: false,
              },
              y: {
                  show: true,
                  max: 100,
                  padding: {
                      top: 10,
                      bottom: 10,
                  }
              }
          },
          bar: {
              width: 16
          },
          tooltip: {
            format: {
              value: function (value, ratio, id, index) {
                  return parseFloat((value * 5).toFixed(2));
              }
            }
          },
          padding: {
            bottom: 20,
            left: 5
          }
      });
    }
  }

})();

$(document).ready(function(){

    // Set up country selector
    $('#available-countries').on('change', function(){
      if (this.value) {
        window.location = '/explore/rtei-country?id=' + this.value;
      }
    });

    // If data available, build the chart
    var chartData = $("#chart").data("chart-data");
    if (chartData) {
      RTEI.country.initChart(chartData);
    }

    // Menu switcher
    $('.indicator-switcher input').on('click', function(){
      RTEI.country.showIndicators(this.value);
    });

    // indicators
    $("#indicators ul").slideUp().parent().addClass("has-children");
    $('#indicators .indicator').click(function(e){
      $(this).parent().children('ul').not(':animated').slideToggle().parent().toggleClass("open");
    });

});
<|endoftext|>


<commit_before>(function() {
    'use strict';

    BlogListController.$inject = ['$scope', '$location', 'api', 'gettext', 'upload',
        'isArchivedFilterSelected', '$q', 'blogSecurityService', 'notify'];
    function BlogListController($scope, $location, api, gettext, upload,
        isArchivedFilterSelected, $q, blogSecurityService, notify) {
        $scope.maxResults = 25;
        $scope.states = [
            {name: 'active', code: 'open', text: gettext('Active blogs')},
            {name: 'archived', code: 'closed', text: gettext('Archived blogs')}
        ];
        $scope.activeState = isArchivedFilterSelected ? $scope.states[1] : $scope.states[0];
        $scope.creationStep = 'Details';
        $scope.requestAccessMessage = gettext('Click to request access');
        $scope.blogMembers = [];
        $scope.changeState = function(state) {
            $scope.activeState = state;
            $location.path('/liveblog/' + state.name);
            fetchBlogs();
        };
        $scope.modalActive = false;

        function clearCreateBlogForm() {
            $scope.preview = {};
            $scope.progress = {width: 0};
            $scope.newBlog = {
                title: '',
                description: ''
            };
            $scope.newBlogError = '';
            $scope.creationStep = 'Details';
            $scope.blogMembers = [];
        }
        clearCreateBlogForm();
        $scope.isAdmin = blogSecurityService.isAdmin;
        $scope.isUserAllowedToCreateABlog = blogSecurityService.canCreateABlog;
        $scope.isUserAllowedToOpenBlog = blogSecurityService.canAccessBlog;
        $scope.cancelCreate = function() {
            clearCreateBlogForm();
            $scope.newBlogModalActive = false;
        };
        $scope.openNewBlog = function() {
            $scope.newBlogModalActive = true;
        };

        $scope.createBlog = function() {
            var members = _.map($scope.blogMembers, function(obj) {
                return {user: obj._id};
            });
            var promise = angular.equals({}, $scope.preview) ? $q.when() : $scope.upload($scope.preview);
            return promise.then(function() {
                return api.blogs.save({
                    title: $scope.newBlog.title,
                    description: $scope.newBlog.description,
                    picture_url: $scope.newBlog.picture_url,
                    picture: $scope.newBlog.picture,
                    members: members
                }).then(function(blog) {
                    $scope.edit(blog);
                }, function(error) {
                    //error handler
                    $scope.newBlogError = gettext('Something went wrong. Please try again later');
                });
            });
        };

        $scope.upload = function(config) {
            var form = {};
            if (config.img) {
                form.media = config.img;
            } else if (config.url) {
                form.URL = config.url;
            } else {
                return;
            }
            // return a promise of upload which will call the success/error callback
            return api.archive.getUrl().then(function(url) {
                return upload.start({
                    method: 'POST',
                    url: url,
                    data: form
                })
                .then(function(response) {
                    if (response.data._status === 'ERR'){
                        return;
                    }
                    var picture_url = response.data.renditions.viewImage.href;
                    $scope.newBlog.picture_url = picture_url;
                    $scope.newBlog.picture = response.data._id;
                }, function(error) {
                    notify.error((error.statusText !== '') ? error.statusText : gettext('There was a problem with your upload'));
                }, function(progress) {
                    $scope.progress.width = Math.round(progress.loaded / progress.total * 100.0);
                });
            });
        };

        $scope.remove = function(blog) {
            _.remove($scope.blogs._items, blog);
        };

        $scope.edit = function(blog) {
            $location.path('/liveblog/edit/' + blog._id);
        };

        $scope.openAccessRequest = function(blog) {
            $scope.accessRequestedTo = blog;
            $scope.showBlogAccessModal = true;
        }

        $scope.closeAccessRequest = function() {
            $scope.accessRequestedTo = false;
            $scope.showBlogAccessModal = false;
        };

        $scope.requestAccess = function(blog) {

            var showRequestDialog = true;
            //check to see if the current user hasn't been accepted during this session (before refreshing)
            if (blog.members) {
                _.each(blog.members, function(member) {
                    if (member.user === $scope.$root.currentUser._id) {
                        showRequestDialog = false;
                    }
                });
            }

            if (showRequestDialog) {
                notify.info(gettext('Sending request'));
                api('request_membership').save({blog: blog._id}).then(
                    function(data) {
                        notify.pop();
                        notify.info(gettext('Request sent'));
                    },
                    function(data) {
                        notify.pop();
                        var message = gettext('Something went wrong, plase try again later!');
                        if (data.data._message === 'A request has already been sent') {
                            message = gettext('A request has already been sent');
                        }
                        notify.error(message, 5000);
                    }
                );
                $scope.closeAccessRequest();
            } else {
                notify.pop();
                notify.error(gettext('You are already member of this blog\'s team'));
            }
        };

        $scope.switchTab = function(newTab) {
            $scope.creationStep = newTab;
        };

        $scope.handleKeyDown = function(event, action) {
            //prevent form submission and editor 'artifact'
            if (event.keyCode === 13) {
                event.preventDefault();
                switch(action) {
                    case 'goToTeamTab':
                        //we need at least a valid title from the first tab
                        if ($scope.newBlog.title) {
                            $scope.switchTab('Team');
                        }
                        break;
                }
            }
        };

        $scope.addMember = function(user) {
            $scope.blogMembers.push(user);
        };

        $scope.removeMember = function(user) {
            $scope.blogMembers.splice($scope.blogMembers.indexOf(user), 1);
        };

        //set grid or list view
        $scope.setBlogsView = function(blogsView) {
            if (typeof blogsView !== 'undefined') {
                $scope.blogsView = blogsView;
                localStorage.setItem('blogsView', blogsView);
            } else {
                if (typeof (localStorage.getItem('blogsView')) === 'undefined' || (localStorage.getItem('blogsView')) === null) {
                    $scope.blogsView = 'grid';
                } else {
                    $scope.blogsView = localStorage.getItem('blogsView');
                }
            }
        };
        $scope.setBlogsView();

        function getCriteria() {
            var params = $location.search(),
                criteria = {
                    max_results: $scope.maxResults,
                    embedded: {'original_creator': 1},
                    sort: '[("versioncreated", -1)]',
                    source: {
                        query: {filtered: {filter: {term: {blog_status: $scope.activeState.code}}}}
                    }
                };
            if (params.q) {
                criteria.source.query.filtered.query = {
                    query_string: {
                        query: '*' + params.q + '*',
                        fields: ['title', 'description']
                    }
                };
            }
            if (params.page) {
                criteria.page = parseInt(params.page, 10);
            }
            return criteria;
        }

        function fetchBlogs() {
            $scope.blogsLoading = true;
            api.blogs.query(getCriteria(), false).then(function(blogs) {
                $scope.blogs = blogs;
                blogs._items.forEach(function(blog) {
                    var criteria = {
                        source: {
                            query: {
                                filtered: {filter: {and: [
                                    {term: {'post_status': 'open'}}, {term: {'blog': blog._id}}
                                ]}}
                            }, sort: [{'published_date': 'asc'}]}
                    };
                    api.posts.query(criteria).then(function(data) {
                    blog.posts_count = data._meta.total;
                    var posts = data._items;
                    posts.forEach(function(post) {
                        blog.last_posted = post.published_date;
                        });
                    });
                });
                $scope.blogsLoading = false;
            });
        }

        // initialize blogs list
        fetchBlogs();
        // fetch when maxResults is updated from the searchbar-directive
        $scope.$watch('maxResults', fetchBlogs);
        // fetch when criteria are updated from url (searchbar-directive)
        $scope.$on('$routeUpdate', fetchBlogs);
    }

    var app = angular.module('liveblog.bloglist', ['liveblog.security']);
    app.config(['apiProvider', function(apiProvider) {
        apiProvider.api('blogs', {
            type: 'http',
            backend: {rel: 'blogs'}
        });
        apiProvider.api('archive', {
            type: 'http',
            backend: {rel: 'archive'}
        });
    }]).config(['superdeskProvider', function(superdesk) {
        superdesk
            .activity('/liveblog', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                category: superdesk.MENU_MAIN,
                adminTools: false,
                resolve: {isArchivedFilterSelected: function() {return false;}}
            }).activity('/liveblog/active', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                resolve: {isArchivedFilterSelected: function() {return false;}}
            }).activity('/liveblog/archived', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                resolve: {isArchivedFilterSelected: function() {return true;}}
            });
    }]);
    app.filter('htmlToPlaintext', function() {
        return function(text) {
            //replace paragraph and list item with an empty space
            var retValue = text ? String(text).replace(/<(p|li)>/g, ' ') : '';
            retValue = retValue.replace(/<[^>]+>/gm, '');
            return retValue.replace(/( )/gm, '');
        };
      }
    );
    app.filter('username', ['session', function usernameFilter(session) {
        return function getUsername(user) {
            return user ? user.display_name || user.username : null;
        };
    }]);
    app.directive('sdPlainImage', ['gettext', 'notify', function(gettext, notify) {
        return {
            scope: {
                src: '=',
                file: '=',
                progressWidth: '='
            },
            link: function(scope, elem) {
                scope.$watch('src', function(src) {
                    elem.empty();
                    if ((scope.file.size / 1048576) > 2) {
                        notify.info(gettext('Blog image is big, upload can take some time!'));
                    }
                    if (src) {
                        var img = new Image();
                        img.onload = function() {
                            scope.progressWidth = 80;

                            if (this.width < 320 || this.height < 240) {
                                scope.$apply(function() {
                                    notify.error(gettext('Sorry, but blog image must be at least 320x240 pixels big!'));
                                    scope.src = null;
                                    scope.progressWidth = 0;
                                });

                                return;
                            }
                            elem.append(img);
                            scope.$apply(function() {
                                scope.progressWidth = 0;
                            });
                        };
                        img.src = src;
                    }
                });
            }
        };
    }]).directive('ifBackgroundImage', function() {
        return {
            restrict: 'A',
            scope: {
                ifBackgroundImage: '@'
            },
            link: function(scope, element, attrs) {
                var url = scope.ifBackgroundImage;
                if (url) {
                    element.css({
                        'background-image': 'url(' + url + ')'
                    });
                }
            }
        };
    })
    .directive('lbUserSelectList', ['$filter', 'api', function($filter, api) {
            return {
                scope: {
                    members: '=',
                    onchoose: '&'
                },
                templateUrl: 'scripts/bower_components/superdesk/client/app/scripts/superdesk-desks/views/user-select.html',
                link: function(scope, elem, attrs) {

                    var ARROW_UP = 38, ARROW_DOWN = 40, ENTER = 13;

                    scope.selected = null;
                    scope.search = null;
                    scope.users = {};

                    var _refresh = function() {
                        scope.users = {};
                        return api('users').query({where: JSON.stringify({
                            '$or': [
                                {username: {'$regex': scope.search, '$options': '-i'}},
                                {first_name: {'$regex': scope.search, '$options': '-i'}},
                                {last_name: {'$regex': scope.search, '$options': '-i'}},
                                {email: {'$regex': scope.search, '$options': '-i'}}
                            ]
                        })})
                        .then(function(result) {
                            scope.users = result;
                            scope.users._items = _.filter(scope.users._items, function(item) {
                                var found = false;
                                _.each(scope.members, function(member) {
                                    if (member._id === item._id) {
                                        found = true;
                                    }
                                });
                                return !found;
                            });
                            scope.selected = null;
                        });
                    };
                    var refresh = _.debounce(_refresh, 1000);

                    scope.$watch('search', function() {
                        if (scope.search) {
                            refresh();
                        }
                    });

                    function getSelectedIndex() {
                        if (scope.selected) {
                            var selectedIndex = -1;
                            _.each(scope.users._items, function(item, index) {
                                if (item === scope.selected) {
                                    selectedIndex = index;
                                }
                            });
                            return selectedIndex;
                        } else {
                            return -1;
                        }
                    }

                    function previous() {
                        var selectedIndex = getSelectedIndex(),
                        previousIndex = _.max([0, selectedIndex - 1]);
                        if (selectedIndex > 0) {
                            scope.select(scope.users._items[previousIndex]);
                        }
                    }

                    function next() {
                        var selectedIndex = getSelectedIndex(),
                        nextIndex = _.min([scope.users._items.length - 1, selectedIndex + 1]);
                        scope.select(scope.users._items[nextIndex]);
                    }

                    elem.bind('keydown keypress', function(event) {
                        scope.$apply(function() {
                            switch (event.which) {
                                case ARROW_UP:
                                    event.preventDefault();
                                    previous();
                                    break;
                                case ARROW_DOWN:
                                    event.preventDefault();
                                    next();
                                    break;
                                case ENTER:
                                    event.preventDefault();
                                    if (getSelectedIndex() >= 0) {
                                        scope.choose(scope.selected);
                                    }
                                    break;
                            }
                        });
                    });

                    scope.choose = function(user) {
                        scope.onchoose({user: user});
                        scope.search = null;
                    };

                    scope.select = function(user) {
                        scope.selected = user;
                    };
                }
            };
        }]);
})();
<commit_msg>Pointing to the wrong path<commit_after>(function() {
    'use strict';

    BlogListController.$inject = ['$scope', '$location', 'api', 'gettext', 'upload',
        'isArchivedFilterSelected', '$q', 'blogSecurityService', 'notify'];
    function BlogListController($scope, $location, api, gettext, upload,
        isArchivedFilterSelected, $q, blogSecurityService, notify) {
        $scope.maxResults = 25;
        $scope.states = [
            {name: 'active', code: 'open', text: gettext('Active blogs')},
            {name: 'archived', code: 'closed', text: gettext('Archived blogs')}
        ];
        $scope.activeState = isArchivedFilterSelected ? $scope.states[1] : $scope.states[0];
        $scope.creationStep = 'Details';
        $scope.requestAccessMessage = gettext('Click to request access');
        $scope.blogMembers = [];
        $scope.changeState = function(state) {
            $scope.activeState = state;
            $location.path('/liveblog/' + state.name);
            fetchBlogs();
        };
        $scope.modalActive = false;

        function clearCreateBlogForm() {
            $scope.preview = {};
            $scope.progress = {width: 0};
            $scope.newBlog = {
                title: '',
                description: ''
            };
            $scope.newBlogError = '';
            $scope.creationStep = 'Details';
            $scope.blogMembers = [];
        }
        clearCreateBlogForm();
        $scope.isAdmin = blogSecurityService.isAdmin;
        $scope.isUserAllowedToCreateABlog = blogSecurityService.canCreateABlog;
        $scope.isUserAllowedToOpenBlog = blogSecurityService.canAccessBlog;
        $scope.cancelCreate = function() {
            clearCreateBlogForm();
            $scope.newBlogModalActive = false;
        };
        $scope.openNewBlog = function() {
            $scope.newBlogModalActive = true;
        };

        $scope.createBlog = function() {
            var members = _.map($scope.blogMembers, function(obj) {
                return {user: obj._id};
            });
            var promise = angular.equals({}, $scope.preview) ? $q.when() : $scope.upload($scope.preview);
            return promise.then(function() {
                return api.blogs.save({
                    title: $scope.newBlog.title,
                    description: $scope.newBlog.description,
                    picture_url: $scope.newBlog.picture_url,
                    picture: $scope.newBlog.picture,
                    members: members
                }).then(function(blog) {
                    $scope.edit(blog);
                }, function(error) {
                    //error handler
                    $scope.newBlogError = gettext('Something went wrong. Please try again later');
                });
            });
        };

        $scope.upload = function(config) {
            var form = {};
            if (config.img) {
                form.media = config.img;
            } else if (config.url) {
                form.URL = config.url;
            } else {
                return;
            }
            // return a promise of upload which will call the success/error callback
            return api.archive.getUrl().then(function(url) {
                return upload.start({
                    method: 'POST',
                    url: url,
                    data: form
                })
                .then(function(response) {
                    if (response.data._status === 'ERR'){
                        return;
                    }
                    var picture_url = response.data.renditions.viewImage.href;
                    $scope.newBlog.picture_url = picture_url;
                    $scope.newBlog.picture = response.data._id;
                }, function(error) {
                    notify.error((error.statusText !== '') ? error.statusText : gettext('There was a problem with your upload'));
                }, function(progress) {
                    $scope.progress.width = Math.round(progress.loaded / progress.total * 100.0);
                });
            });
        };

        $scope.remove = function(blog) {
            _.remove($scope.blogs._items, blog);
        };

        $scope.edit = function(blog) {
            $location.path('/liveblog/edit/' + blog._id);
        };

        $scope.openAccessRequest = function(blog) {
            $scope.accessRequestedTo = blog;
            $scope.showBlogAccessModal = true;
        }

        $scope.closeAccessRequest = function() {
            $scope.accessRequestedTo = false;
            $scope.showBlogAccessModal = false;
        };

        $scope.requestAccess = function(blog) {

            var showRequestDialog = true;
            //check to see if the current user hasn't been accepted during this session (before refreshing)
            if (blog.members) {
                _.each(blog.members, function(member) {
                    if (member.user === $scope.$root.currentUser._id) {
                        showRequestDialog = false;
                    }
                });
            }

            if (showRequestDialog) {
                notify.info(gettext('Sending request'));
                api('request_membership').save({blog: blog._id}).then(
                    function(data) {
                        notify.pop();
                        notify.info(gettext('Request sent'));
                    },
                    function(data) {
                        notify.pop();
                        var message = gettext('Something went wrong, plase try again later!');
                        if (data.data._message === 'A request has already been sent') {
                            message = gettext('A request has already been sent');
                        }
                        notify.error(message, 5000);
                    }
                );
                $scope.closeAccessRequest();
            } else {
                notify.pop();
                notify.error(gettext('You are already member of this blog\'s team'));
            }
        };

        $scope.switchTab = function(newTab) {
            $scope.creationStep = newTab;
        };

        $scope.handleKeyDown = function(event, action) {
            //prevent form submission and editor 'artifact'
            if (event.keyCode === 13) {
                event.preventDefault();
                switch(action) {
                    case 'goToTeamTab':
                        //we need at least a valid title from the first tab
                        if ($scope.newBlog.title) {
                            $scope.switchTab('Team');
                        }
                        break;
                }
            }
        };

        $scope.addMember = function(user) {
            $scope.blogMembers.push(user);
        };

        $scope.removeMember = function(user) {
            $scope.blogMembers.splice($scope.blogMembers.indexOf(user), 1);
        };

        //set grid or list view
        $scope.setBlogsView = function(blogsView) {
            if (typeof blogsView !== 'undefined') {
                $scope.blogsView = blogsView;
                localStorage.setItem('blogsView', blogsView);
            } else {
                if (typeof (localStorage.getItem('blogsView')) === 'undefined' || (localStorage.getItem('blogsView')) === null) {
                    $scope.blogsView = 'grid';
                } else {
                    $scope.blogsView = localStorage.getItem('blogsView');
                }
            }
        };
        $scope.setBlogsView();

        function getCriteria() {
            var params = $location.search(),
                criteria = {
                    max_results: $scope.maxResults,
                    embedded: {'original_creator': 1},
                    sort: '[("versioncreated", -1)]',
                    source: {
                        query: {filtered: {filter: {term: {blog_status: $scope.activeState.code}}}}
                    }
                };
            if (params.q) {
                criteria.source.query.filtered.query = {
                    query_string: {
                        query: '*' + params.q + '*',
                        fields: ['title', 'description']
                    }
                };
            }
            if (params.page) {
                criteria.page = parseInt(params.page, 10);
            }
            return criteria;
        }

        function fetchBlogs() {
            $scope.blogsLoading = true;
            api.blogs.query(getCriteria(), false).then(function(blogs) {
                $scope.blogs = blogs;
                blogs._items.forEach(function(blog) {
                    var criteria = {
                        source: {
                            query: {
                                filtered: {filter: {and: [
                                    {term: {'post_status': 'open'}}, {term: {'blog': blog._id}}
                                ]}}
                            }, sort: [{'published_date': 'asc'}]}
                    };
                    api.posts.query(criteria).then(function(data) {
                    blog.posts_count = data._meta.total;
                    var posts = data._items;
                    posts.forEach(function(post) {
                        blog.last_posted = post.published_date;
                        });
                    });
                });
                $scope.blogsLoading = false;
            });
        }

        // initialize blogs list
        fetchBlogs();
        // fetch when maxResults is updated from the searchbar-directive
        $scope.$watch('maxResults', fetchBlogs);
        // fetch when criteria are updated from url (searchbar-directive)
        $scope.$on('$routeUpdate', fetchBlogs);
    }

    var app = angular.module('liveblog.bloglist', ['liveblog.security']);
    app.config(['apiProvider', function(apiProvider) {
        apiProvider.api('blogs', {
            type: 'http',
            backend: {rel: 'blogs'}
        });
        apiProvider.api('archive', {
            type: 'http',
            backend: {rel: 'archive'}
        });
    }]).config(['superdeskProvider', function(superdesk) {
        superdesk
            .activity('/liveblog', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                category: superdesk.MENU_MAIN,
                adminTools: false,
                resolve: {isArchivedFilterSelected: function() {return false;}}
            }).activity('/liveblog/active', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                resolve: {isArchivedFilterSelected: function() {return false;}}
            }).activity('/liveblog/archived', {
                label: gettext('Blog List'),
                controller: BlogListController,
                templateUrl: 'scripts/liveblog-bloglist/views/main.html',
                resolve: {isArchivedFilterSelected: function() {return true;}}
            });
    }]);
    app.filter('htmlToPlaintext', function() {
        return function(text) {
            //replace paragraph and list item with an empty space
            var retValue = text ? String(text).replace(/<(p|li)>/g, ' ') : '';
            retValue = retValue.replace(/<[^>]+>/gm, '');
            return retValue.replace(/( )/gm, '');
        };
      }
    );
    app.filter('username', ['session', function usernameFilter(session) {
        return function getUsername(user) {
            return user ? user.display_name || user.username : null;
        };
    }]);
    app.directive('sdPlainImage', ['gettext', 'notify', function(gettext, notify) {
        return {
            scope: {
                src: '=',
                file: '=',
                progressWidth: '='
            },
            link: function(scope, elem) {
                scope.$watch('src', function(src) {
                    elem.empty();
                    if ((scope.file.size / 1048576) > 2) {
                        notify.info(gettext('Blog image is big, upload can take some time!'));
                    }
                    if (src) {
                        var img = new Image();
                        img.onload = function() {
                            scope.progressWidth = 80;

                            if (this.width < 320 || this.height < 240) {
                                scope.$apply(function() {
                                    notify.error(gettext('Sorry, but blog image must be at least 320x240 pixels big!'));
                                    scope.src = null;
                                    scope.progressWidth = 0;
                                });

                                return;
                            }
                            elem.append(img);
                            scope.$apply(function() {
                                scope.progressWidth = 0;
                            });
                        };
                        img.src = src;
                    }
                });
            }
        };
    }]).directive('ifBackgroundImage', function() {
        return {
            restrict: 'A',
            scope: {
                ifBackgroundImage: '@'
            },
            link: function(scope, element, attrs) {
                var url = scope.ifBackgroundImage;
                if (url) {
                    element.css({
                        'background-image': 'url(' + url + ')'
                    });
                }
            }
        };
    })
    .directive('lbUserSelectList', ['$filter', 'api', function($filter, api) {
            return {
                scope: {
                    members: '=',
                    onchoose: '&'
                },
                templateUrl: 'scripts/apps/desks/views/user-select.html',
                link: function(scope, elem, attrs) {

                    var ARROW_UP = 38, ARROW_DOWN = 40, ENTER = 13;

                    scope.selected = null;
                    scope.search = null;
                    scope.users = {};

                    var _refresh = function() {
                        scope.users = {};
                        return api('users').query({where: JSON.stringify({
                            '$or': [
                                {username: {'$regex': scope.search, '$options': '-i'}},
                                {first_name: {'$regex': scope.search, '$options': '-i'}},
                                {last_name: {'$regex': scope.search, '$options': '-i'}},
                                {email: {'$regex': scope.search, '$options': '-i'}}
                            ]
                        })})
                        .then(function(result) {
                            scope.users = result;
                            scope.users._items = _.filter(scope.users._items, function(item) {
                                var found = false;
                                _.each(scope.members, function(member) {
                                    if (member._id === item._id) {
                                        found = true;
                                    }
                                });
                                return !found;
                            });
                            scope.selected = null;
                        });
                    };
                    var refresh = _.debounce(_refresh, 1000);

                    scope.$watch('search', function() {
                        if (scope.search) {
                            refresh();
                        }
                    });

                    function getSelectedIndex() {
                        if (scope.selected) {
                            var selectedIndex = -1;
                            _.each(scope.users._items, function(item, index) {
                                if (item === scope.selected) {
                                    selectedIndex = index;
                                }
                            });
                            return selectedIndex;
                        } else {
                            return -1;
                        }
                    }

                    function previous() {
                        var selectedIndex = getSelectedIndex(),
                        previousIndex = _.max([0, selectedIndex - 1]);
                        if (selectedIndex > 0) {
                            scope.select(scope.users._items[previousIndex]);
                        }
                    }

                    function next() {
                        var selectedIndex = getSelectedIndex(),
                        nextIndex = _.min([scope.users._items.length - 1, selectedIndex + 1]);
                        scope.select(scope.users._items[nextIndex]);
                    }

                    elem.bind('keydown keypress', function(event) {
                        scope.$apply(function() {
                            switch (event.which) {
                                case ARROW_UP:
                                    event.preventDefault();
                                    previous();
                                    break;
                                case ARROW_DOWN:
                                    event.preventDefault();
                                    next();
                                    break;
                                case ENTER:
                                    event.preventDefault();
                                    if (getSelectedIndex() >= 0) {
                                        scope.choose(scope.selected);
                                    }
                                    break;
                            }
                        });
                    });

                    scope.choose = function(user) {
                        scope.onchoose({user: user});
                        scope.search = null;
                    };

                    scope.select = function(user) {
                        scope.selected = user;
                    };
                }
            };
        }]);
})();
<|endoftext|>


<commit_before>'use strict';

angular.module('venueApp')
  .controller('UploadCtrl', function ($scope) {
    $scope.message = 'Hello';
  });
<commit_msg>added service to upload<commit_after>'use strict';

angular.module('venueApp')
  .controller('UploadCtrl', function ($scope, Submission) {
    $scope.message = 'Hello';
  });
<|endoftext|>


<commit_before>import Home from '../pages/home.page'
import { expect } from 'chai'

describe('Anet user login', () => {
	it('Default user is logged in"', () => {
		Home.open()
		Home.securityBanner.waitForExist()
		Home.securityBanner.waitForVisible()
		const securityText = Home.securityBanner.getText()
		expect(securityText).to.equal('DEMO USE ONLY || ERINSON, Erin (edit)')
	})

	it('Super user is logged in"', () => {
		Home.openAsSuperUser()
		Home.securityBanner.waitForExist()
		Home.securityBanner.waitForVisible()
		const securityText = Home.securityBanner.getText()
		expect(securityText).to.equal('DEMO USE ONLY || DMIN, Arthur (edit)')
	})
})
<commit_msg>NCI-Agency/anet#329: Split tests with different credentials in separate suites<commit_after>import Home from '../pages/home.page'
import { expect } from 'chai'

describe('Anet default user login', () => {
	it('Default user is logged in"', () => {
		Home.open()
		Home.securityBanner.waitForExist()
		Home.securityBanner.waitForVisible()
		const securityText = Home.securityBanner.getText()
		expect(securityText).to.equal('DEMO USE ONLY || ERINSON, Erin (edit)')
	})
})

describe('Anet super user login', () => {
	it('Super user is logged in"', () => {
		Home.openAsSuperUser()
		Home.securityBanner.waitForExist()
		Home.securityBanner.waitForVisible()
		const securityText = Home.securityBanner.getText()
		expect(securityText).to.equal('DEMO USE ONLY || DMIN, Arthur (edit)')
	})
})
<|endoftext|>