<commit_before>"use strict";

var documentClient = require("documentdb").DocumentClient;
var config = require("./config");
var url = require('url');
var http = require('http');

var lib = require("./node_modules/documentdb/lib/");
var connectionPolicy = new lib.DocumentBase.ConnectionPolicy();
connectionPolicy.EnableEndpointDiscovery = 'True';

var client = new documentClient(config.endpoint, { "masterKey": config.primaryKey }, connectionPolicy);

var databaseUrl = `dbs/${config.database.id}`;
var collectionUrl = `${databaseUrl}/colls/${config.collection.id}`;

//client.deleteDatabase(`dbs/${databaseId}`, callback);

var read = documentClient.getReadEndpoint;
var write = documentClient.getWriteEndpoint;

var server = http.createServer(function(request, response) {

    response.writeHead(200, {"Content-Type": "text/plain"});

    response.write('Write endpoint is: ' + read);
    response.write('\nRead endpoint is: ' + read + '\n\n');

    client.queryDocuments(
            collectionUrl,
            'SELECT c.description,c.cost FROM c'
        ).toArray((err, results) => {
            if (err) reject(err)
            else {
                for (var queryResult of results) {
                    response.write('Name: ' + queryResult.description + '\n');
                    response.write('Cost: $' + queryResult.cost+ '\n\n');
                }
                response.end();
            }
        });
});

var port = process.env.PORT || 3000;
server.listen(port);

console.log("Server running at http://localhost:%d", port);
<commit_msg>Adding geo replication output and code comments<commit_after>"use strict";

var config = require("./config");
var url = require('url');
var http = require('http');

// Create a connection to Cosmos DB
// Here, we use the Document model, and define a connection policy
var documentClient = require("documentdb").DocumentClient;
var lib = require("./node_modules/documentdb/lib/");

// The connection policy can use automatic endpoint discovery, or you can specify a list
// of preferred endpoints.
var connectionPolicy = new lib.DocumentBase.ConnectionPolicy();

// Using automatic discovery is a more dynamic approach, and your code requires no changes
// as you add or remove endpoints in Cosmos DB
//connectionPolicy.EnableEndpointDiscovery = 'True';

// Using a list of preferred locations allows you to control the order in which endpoints
// are used. In our example, we selected 'West Europe' as an additional endpoint. By then
// setting 'West Europe' as our preferred location, although all writes still go through the
// the primary endpoint of 'East US', all reads go through 'West Europe'.
connectionPolicy.PreferredLocations = ['West Europe', 'East US'];

// Now actually make the connection to Cosmos DB using our endpoint, key, and connection policy
var client = new documentClient(config.endpoint, { "masterKey": config.primaryKey }, connectionPolicy);
var databaseUrl = `dbs/${config.database.id}`;
var collectionUrl = `${databaseUrl}/colls/${config.collection.id}`;

// Start a basic HTTP server in Node.js for our basic web app
var server = http.createServer(function(request, response) {

    // Start to write a basic HTTP response to render our page
    response.writeHead(200, {"Content-Type": "text/plain"});

    // Output the current write endpoint
    // This is the endpoint where all write requests route through to ensure data consistency
    client.getWriteEndpoint(function(endpoint) {
        response.write('Current write endpoint is: ' + endpoint + '\n');
    });

    // Output the current read endpoint
    // This is the power of Cosmos DB. The APIs determine the closest read endpoint and route your
    // requests accordingly. There's nothing your app does here.
    // This is purely for informational purposes. You just query the database in the next code block
    // and let the APIs determine the most appropriate endpoint to pull data from.
    client.getReadEndpoint(function(endpoint) {
        response.write('Current read endpoint is: ' + endpoint + '\n\n');
    });

    // Query the database to obtain a basic list of pizzas and their costs
    // This can be expanded to sort by price or alphabetically by pizza name, for example
    client.queryDocuments(
            collectionUrl,
            'SELECT c.description,c.cost FROM c'
        ).toArray((err, results) => {
            if (err) reject(err)
            else {

                for (var queryResult of results) {
                    response.write('Name: ' + queryResult.description + '\n');
                    response.write('Cost: $' + queryResult.cost+ '\n\n');
                }
                response.end();
            }
        });
});

// Start the web server listening on port 3000
// If you use Azure Web Apps, this port is mapped back to port 80 so that's all you need to
// enter in your web browser
var port = process.env.PORT || 3000;
server.listen(port);

console.log("Server running at http://localhost:%d", port);
<|endoftext|>


<commit_before>/**
 * EventEmitter v4.0.0 - github.com/Wolfy87/EventEmitter
 *
 * Oliver Caldwell
 * MIT license
 */

;(function(exports) {
    // JSHint config - http://www.jshint.com/
    /*global define:true*/

    // Place the script in strict mode
    'use strict';

    /**
     * Class for managing events.
     * Can be extended to provide event functionality in other classes.
     *
     * @class Manages event registering and emitting.
     */
    function EventEmitter(){}

    /**
     * Provides a shortcut to the prototype.
     *
     * @property {Object} Shortcut to the prototype object.
     */
    EventEmitter.fn = EventEmitter.prototype;

    /**
     * Returns the listener array for the specified event.
     * Will initialise the event object and listener arrays if required.
     *
     * @param {String} evt Name of the event to return the listeners from.
     * @returns {Function[]} All listener functions for the event.
     */
    EventEmitter.fn.getListeners = function(evt) {
        // Create a shortcut to the storage object
        // Initialise it if it does not exists yet
        var events = this._events || (this._events = {});

        // Return the listener array
        // Initialise it if it does not exist
        return events[evt] || (events[evt] = []);
    };

    /**
     * Finds the index of the listener for the event in it's storage array
     *
     * @param {Function} listener Method to look for.
     * @param {Function[]} listeners Array of listeners to search through.
     * @returns {Number} Index of the specified listener, -1 if not found
     */
    EventEmitter.fn.indexOfListener = function(listener, listeners) {
        // Return the index via the native method if possible
        if(listeners.indexOf) {
            return listeners.indexOf(listener);
        }

        // There is no native method
        // Use a manual loop to find the index
        var i = listeners.length;
        while(i--) {
            // If the listener matches, return it's index
            if(listeners[i] === listener) {
                return i;
            }
        }

        // Default to returning -1
        return -1;
    };

    /**
     * Adds a listener function to the specified event.
     * The listener will not be added if it is a duplicate.
     *
     * @param {String} evt Name of the event to attach the listener to.
     * @param {Function} listener Method to be called when the event is emitted.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.addListener = function(evt, listener) {
        // Fetch the listeners
        var listeners = this.getListeners(evt);

        // Push the listener into the array if it is not already there
        if(this.indexOfListener(listener, listeners) === -1) {
            listeners.push(listener);
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Removes a listener function from the specified event.
     *
     * @param {String} evt Name of the event to remove the listener from.
     * @param {Function} listener Method to remove from the event.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.removeListener = function(evt, listener) {
        // Fetch the listeners
        // And get the index of the listener in the array
        var listeners = this.getListeners(evt),
            index = this.indexOfListener(listener, listeners);

        // If the listener was found then remove it
        if(index !== -1) {
            listeners.splice(index, 1);

            // If there are no more listeners in this array then remove it
            if(listeners.length === 0) {
                delete this._events[evt];
            }
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Removes all listeners from a specified event.
     * If you do not specify an event then all listeners will be removed.
     * That means every event will be emptied.
     *
     * @param {String} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.removeListeners = function(evt) {
        // Remove different things depending on the state of evt
        if(evt) {
            // Remove all listeners for the specified event
            delete this._events[evt];
        }
        else {
            // Remove all listeners in all events
            delete this._events;
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Emits an event of your choice.
     * When emitted, every listener attached to that event will be executed.
     * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
     * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
     * So they will not arrive within the array on the other side, they will be separate.
     *
     * @param {String} evt Name of the event to emit and execute listeners for.
     * @param {Array} [args] Optional array of arguments to be passed to each argument.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.emitEvent = function(evt, args) {
        // Get the listeners for the event
        // Also initialise any other required variables
        var listeners = this.getListeners(evt),
            i = listeners.length;

        while(i--) {
            // Execute every listener attached to the event
            // Apply the arguments array to each listener too
            listeners[i].apply(null, args);
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    // Expose the class either via AMD or the global object
    if(typeof define === 'function' && define.amd) {
        define(function() {
            return EventEmitter;
        });
    }
    else {
        exports.EventEmitter = EventEmitter;
    }
}(this));<commit_msg>Removed a blank line from the header comment. I just want it to be a little smaller.<commit_after>/**
 * EventEmitter v4.0.0 - github.com/Wolfy87/EventEmitter
 * Oliver Caldwell
 * MIT license
 */

;(function(exports) {
    // JSHint config - http://www.jshint.com/
    /*global define:true*/

    // Place the script in strict mode
    'use strict';

    /**
     * Class for managing events.
     * Can be extended to provide event functionality in other classes.
     *
     * @class Manages event registering and emitting.
     */
    function EventEmitter(){}

    /**
     * Provides a shortcut to the prototype.
     *
     * @property {Object} Shortcut to the prototype object.
     */
    EventEmitter.fn = EventEmitter.prototype;

    /**
     * Returns the listener array for the specified event.
     * Will initialise the event object and listener arrays if required.
     *
     * @param {String} evt Name of the event to return the listeners from.
     * @returns {Function[]} All listener functions for the event.
     */
    EventEmitter.fn.getListeners = function(evt) {
        // Create a shortcut to the storage object
        // Initialise it if it does not exists yet
        var events = this._events || (this._events = {});

        // Return the listener array
        // Initialise it if it does not exist
        return events[evt] || (events[evt] = []);
    };

    /**
     * Finds the index of the listener for the event in it's storage array
     *
     * @param {Function} listener Method to look for.
     * @param {Function[]} listeners Array of listeners to search through.
     * @returns {Number} Index of the specified listener, -1 if not found
     */
    EventEmitter.fn.indexOfListener = function(listener, listeners) {
        // Return the index via the native method if possible
        if(listeners.indexOf) {
            return listeners.indexOf(listener);
        }

        // There is no native method
        // Use a manual loop to find the index
        var i = listeners.length;
        while(i--) {
            // If the listener matches, return it's index
            if(listeners[i] === listener) {
                return i;
            }
        }

        // Default to returning -1
        return -1;
    };

    /**
     * Adds a listener function to the specified event.
     * The listener will not be added if it is a duplicate.
     *
     * @param {String} evt Name of the event to attach the listener to.
     * @param {Function} listener Method to be called when the event is emitted.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.addListener = function(evt, listener) {
        // Fetch the listeners
        var listeners = this.getListeners(evt);

        // Push the listener into the array if it is not already there
        if(this.indexOfListener(listener, listeners) === -1) {
            listeners.push(listener);
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Removes a listener function from the specified event.
     *
     * @param {String} evt Name of the event to remove the listener from.
     * @param {Function} listener Method to remove from the event.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.removeListener = function(evt, listener) {
        // Fetch the listeners
        // And get the index of the listener in the array
        var listeners = this.getListeners(evt),
            index = this.indexOfListener(listener, listeners);

        // If the listener was found then remove it
        if(index !== -1) {
            listeners.splice(index, 1);

            // If there are no more listeners in this array then remove it
            if(listeners.length === 0) {
                delete this._events[evt];
            }
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Removes all listeners from a specified event.
     * If you do not specify an event then all listeners will be removed.
     * That means every event will be emptied.
     *
     * @param {String} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.removeListeners = function(evt) {
        // Remove different things depending on the state of evt
        if(evt) {
            // Remove all listeners for the specified event
            delete this._events[evt];
        }
        else {
            // Remove all listeners in all events
            delete this._events;
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    /**
     * Emits an event of your choice.
     * When emitted, every listener attached to that event will be executed.
     * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
     * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
     * So they will not arrive within the array on the other side, they will be separate.
     *
     * @param {String} evt Name of the event to emit and execute listeners for.
     * @param {Array} [args] Optional array of arguments to be passed to each argument.
     * @returns {Object} Current instance of EventEmitter for chaining.
     */
    EventEmitter.fn.emitEvent = function(evt, args) {
        // Get the listeners for the event
        // Also initialise any other required variables
        var listeners = this.getListeners(evt),
            i = listeners.length;

        while(i--) {
            // Execute every listener attached to the event
            // Apply the arguments array to each listener too
            listeners[i].apply(null, args);
        }

        // Return the instance of EventEmitter to allow chaining
        return this;
    };

    // Expose the class either via AMD or the global object
    if(typeof define === 'function' && define.amd) {
        define(function() {
            return EventEmitter;
        });
    }
    else {
        exports.EventEmitter = EventEmitter;
    }
}(this));<|endoftext|>


<commit_before>/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */

/**
 * Provides live results to the web client. Maintains a continuous request/response cycle.
 */
(function($) {

  /** @constructor */
  function LiveResultsClient() {

    var self = this;

    var _logger = new Logger("LiveResultsClient", "debug");
    var _cometd = $.cometd;

    var _isConnected = false;

    var _inBatch = false;
    var _batchMetadata = null;
    var _batchPortfolioUpdate;
    var _batchPrimitivesUpdate;

    var _primitivesEventHandler = null;
    var _portfolioEventHandler = null;

    var _awaitingImmediateUpdate = false;
    var _immediateUpdateNextCycle = false;

    var _changingView = false;
    var _isRunning = false;
    var _gridStructure;

    function init() {
      // Kick everything off
      var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
      _cometd.configure({
        url : cometURL,
        logLevel : 'warn'
      });
      _cometd.addListener('/meta/connect', handleMetaConnect);
    }

    //-----------------------------------------------------------------------
    // Response handlers

    function handleMetaConnect(message) {
      if (!_isConnected && message.successful) {
        _isConnected = true;
        _cometd.batch(function() {
          _cometd.subscribe('/status', handleStatusUpdate);
          _cometd.subscribe('/views', handleViewListUpdate);
          _cometd.subscribe('/initialize', handleViewInitialized);

          _cometd.subscribe('/updates/portfolio', handlePortfolioUpdate);
          _cometd.subscribe('/updates/primitives', handlePrimitivesUpdate);

          // Updates to the columns
          _cometd.subscribe('/gridStructure/portfolio/columns', handlePortfolioGridColumns);
          _cometd.subscribe('/gridStructure/primitives/columns', handlePrimitivesGridColumns);

          _cometd.subscribe('/updates/control/**', handleUpdatesControlMessage);
        });
        self.onConnected.fire();
      } else if (_isConnected && !message.successful) {
        _isConnected = false;
        self.onDisconnected.fire();
      }
    }

    function handleStatusUpdate(message) {
      if (_changingView) {
        // An update from the last view
        return;
      }

      self.onStatusUpdateReceived.fire(message.data);

      var isRunning = message.data.isRunning;
      if (_isRunning != isRunning) {
        _isRunning = isRunning;
        if (isRunning) {
          // Kick off the update cycle
          sendUpdateRequest(true);
        }
      }
    }

    function handleViewListUpdate(message) {
      self.onViewListReceived.fire(message.data.availableViewNames);
    }

    function handleViewInitialized(message) {
      _changingView = false;

      if (message.data.primitives) {
        assignFormatters(message.data.primitives.columns);
      }
      if (message.data.portfolio) {
        assignFormatters(message.data.portfolio.columns);
      }

      _gridStructures = message.data;
      self.onViewInitialized.fire(_gridStructures);
    }

    function assignFormatters(columns) {
      $.each(columns, function(index, column) {
        column.typeFormatter = ColumnFormatter.getTypeFormatter(column.dataType);
      });
    }

    function handlePortfolioGridColumns(message) {
      assignFormatters(message.data);
      $.extend(true, _gridStructures.portfolio.columns, message.data);
    }

    function handlePrimitivesGridColumns(message) {
      assignFormatters(message.data);
      $.extend(true, _gridStructures.primitives.columns, message.data);
    }

    function handleUpdatesControlMessage(message) {
      if (message.channel == '/updates/control/start') {
        if (_inBatch) {
          _logger.warn('Already in batch when received start message');
        }
        _inBatch = true;
        _batchMetadata = message.data;
        _batchPortfolioUpdate = new Array();
        _batchPrimitivesUpdate = new Array();
      } else if (message.channel == '/updates/control/end') {
        if (!_inBatch) {
          _logger.warn('Batch flag already cleared before END message');
        }

        handleUpdate(_primitivesEventHandler, _batchPrimitivesUpdate, _batchMetadata.timestamp, _batchMetadata.latency);
        handleUpdate(_portfolioEventHandler, _batchPortfolioUpdate, _batchMetadata.timestamp, _batchMetadata.latency);

        self.afterUpdateReceived.fire(_batchMetadata);

        _inBatch = false;
        _batchMetadata = null;
        _batchPortfolioUpdate = null;
        _batchPrimitivesUpdate = null;
        _awaitingImmediateUpdate = false;

        if (_isRunning) {
          if (_immediateUpdateNextCycle) {
            _immediateUpdateNextCycle = false;
            sendUpdateRequest(true);
          } else {
            sendUpdateRequest(false);
          }
        }
      }
    }

    function handleUpdate(eventHandler, update, timestamp, latency) {
      if (!eventHandler) {
        return;
      }
      eventHandler.updateReceived(update, timestamp, latency);
    }

    function handlePortfolioUpdate(message) {
      if (!_inBatch) {
        _logger.warn('Update received when not in batch');
        return;
      }
      _batchPortfolioUpdate.push(message.data);
    }

    function handlePrimitivesUpdate(message) {
      if (!_inBatch) {
        _logger.warn('Update received when not in batch');
        return;
      }
      _batchPrimitivesUpdate.push(message.data);
    }

    //-----------------------------------------------------------------------
    // Request senders

    function sendUpdateRequest(immediateResponse) {
      if (_awaitingImmediateUpdate) {
        // Already waiting for an immediate update - queue another one
        // Prevents the client from being flooded with update responses
        _immediateUpdateNextCycle = true;
        return;
      }

      if (immediateResponse) {
        _awaitingImmediateUpdate = true;
      }

      var updateMetadata = {
          portfolioViewport : {},
          primitiveViewport : {},
      }

      // Get the UI components to complete the metadata
      self.beforeUpdateRequested.fire(updateMetadata);

      // Send the request
      updateMetadata.immediateResponse = immediateResponse;
      _cometd.publish('/service/updates', updateMetadata);
    }

    function sendUpdateMode(gridName, rowId, colId, mode) {
      _cometd.publish('/service/updates/mode', {
        gridName: gridName,
        rowId: rowId,
        colId: colId,
        mode: mode
      });
    }

    //-----------------------------------------------------------------------
    // Public API

    this.changeView = function(viewName) {
      _logger.info("Sending initialize request");
      _portfolioDetails = null;
      _primitiveDetails = null;
      _changingView = true;
      _isRunning = false;

      _cometd.publish('/service/initialize', {
        viewName : viewName
      });
    }

    this.pause = function() {
      _cometd.publish('/service/currentview/pause', {});
    }

    this.resume = function() {
      _cometd.publish('/service/currentview/resume', {});
    }

    this.getViews = function() {
      _cometd.publish('/service/views', {});
    }

    this.triggerImmediateUpdate = function() {
      sendUpdateRequest(true);
    }

    this.startDetailedCellUpdates = function(gridName, rowId, colId) {
      sendUpdateMode(gridName, rowId, colId, "FULL");
    }

    this.stopDetailedCellUpdates = function(gridName, rowId, colId) {
      sendUpdateMode(gridName, rowId, colId, "SUMMARY");
    }

    this.connect = function() {
      _cometd.handshake();
    }

    this.disconnect = function() {
      _cometd.disconnect();
    }

    this.onConnected = new EventManager();
    this.onDisconnected = new EventManager();

    /**
     * Fired before a update is requested to allow UI components to contribute to the request, for example by inserting
     * viewport details. This way, multiple UI components can consume the same type of data while maintaining requests
     * for the minimum possible set of data.
     */
    this.beforeUpdateRequested = new EventManager();

    this.onViewListReceived = new EventManager();
    this.onViewInitialized = new EventManager();
    this.onStatusUpdateReceived = new EventManager();
    this.afterUpdateReceived = new EventManager();

    this.setPortfolioEventHandler = function(portfolioEventHandler) {
      _portfolioEventHandler = portfolioEventHandler;
    }

    this.setPrimitivesEventHandler = function(primitivesEventHandler) {
      _primitivesEventHandler = primitivesEventHandler;
    }

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

    init();
  }

  $.extend(true, window, {
      LiveResultsClient : LiveResultsClient
  });

}(jQuery));<commit_msg>Bug fix<commit_after>/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */

/**
 * Provides live results to the web client. Maintains a continuous request/response cycle.
 */
(function($) {

  /** @constructor */
  function LiveResultsClient() {

    var self = this;

    var _logger = new Logger("LiveResultsClient", "debug");
    var _cometd = $.cometd;

    var _isConnected = false;

    var _inBatch = false;
    var _batchMetadata = null;
    var _batchPortfolioUpdate;
    var _batchPrimitivesUpdate;

    var _primitivesEventHandler = null;
    var _portfolioEventHandler = null;

    var _awaitingImmediateUpdate = false;
    var _immediateUpdateNextCycle = false;

    var _changingView = false;
    var _isRunning = false;
    var _gridStructure;

    function init() {
      // Kick everything off
      var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
      _cometd.configure({
        url : cometURL,
        logLevel : 'warn'
      });
      _cometd.addListener('/meta/connect', handleMetaConnect);
    }

    //-----------------------------------------------------------------------
    // Response handlers

    function handleMetaConnect(message) {
      if (!_isConnected && message.successful) {
        _isConnected = true;
        _cometd.batch(function() {
          _cometd.subscribe('/status', handleStatusUpdate);
          _cometd.subscribe('/views', handleViewListUpdate);
          _cometd.subscribe('/initialize', handleViewInitialized);

          _cometd.subscribe('/updates/portfolio', handlePortfolioUpdate);
          _cometd.subscribe('/updates/primitives', handlePrimitivesUpdate);

          // Updates to the columns
          _cometd.subscribe('/gridStructure/portfolio/columns', handlePortfolioGridColumns);
          _cometd.subscribe('/gridStructure/primitives/columns', handlePrimitivesGridColumns);

          _cometd.subscribe('/updates/control/**', handleUpdatesControlMessage);
        });
        self.onConnected.fire();
      } else if (_isConnected && !message.successful) {
        _isConnected = false;
        self.onDisconnected.fire();
      }
    }

    function handleStatusUpdate(message) {
      if (_changingView) {
        // An update from the last view
        return;
      }

      self.onStatusUpdateReceived.fire(message.data);

      var isRunning = message.data.isRunning;
      if (_isRunning != isRunning) {
        _isRunning = isRunning;
        if (isRunning) {
          // Kick off the update cycle
          sendUpdateRequest(true);
        }
      }
    }

    function handleViewListUpdate(message) {
      self.onViewListReceived.fire(message.data.availableViewNames);
    }

    function handleViewInitialized(message) {
      _changingView = false;

      if (message.data.primitives) {
        assignFormatters(message.data.primitives.columns);
      }
      if (message.data.portfolio) {
        assignFormatters(message.data.portfolio.columns);
      }

      _gridStructures = message.data;
      self.onViewInitialized.fire(_gridStructures);
    }

    function assignFormatters(columns) {
      $.each(columns, function(index, column) {
        column.typeFormatter = ColumnFormatter.getTypeFormatter(column.dataType);
      });
    }

    function handlePortfolioGridColumns(message) {
      assignFormatters(message.data);
      $.extend(true, _gridStructures.portfolio.columns, message.data);
    }

    function handlePrimitivesGridColumns(message) {
      assignFormatters(message.data);
      $.extend(true, _gridStructures.primitives.columns, message.data);
    }

    function handleUpdatesControlMessage(message) {
      if (message.channel == '/updates/control/start') {
        if (_inBatch) {
          _logger.warn('Already in batch when received start message');
        }
        _inBatch = true;
        _batchMetadata = message.data;
        _batchPortfolioUpdate = new Array();
        _batchPrimitivesUpdate = new Array();
      } else if (message.channel == '/updates/control/end') {
        if (!_inBatch) {
          _logger.warn('Batch flag already cleared before END message');
          return;
        }

        handleUpdate(_primitivesEventHandler, _batchPrimitivesUpdate, _batchMetadata.timestamp, _batchMetadata.latency);
        handleUpdate(_portfolioEventHandler, _batchPortfolioUpdate, _batchMetadata.timestamp, _batchMetadata.latency);

        self.afterUpdateReceived.fire(_batchMetadata);

        _inBatch = false;
        _batchMetadata = null;
        _batchPortfolioUpdate = null;
        _batchPrimitivesUpdate = null;
        _awaitingImmediateUpdate = false;

        if (_isRunning) {
          if (_immediateUpdateNextCycle) {
            _immediateUpdateNextCycle = false;
            sendUpdateRequest(true);
          } else {
            sendUpdateRequest(false);
          }
        }
      }
    }

    function handleUpdate(eventHandler, update, timestamp, latency) {
      if (!eventHandler) {
        return;
      }
      eventHandler.updateReceived(update, timestamp, latency);
    }

    function handlePortfolioUpdate(message) {
      if (!_inBatch) {
        _logger.warn('Update received when not in batch');
        return;
      }
      _batchPortfolioUpdate.push(message.data);
    }

    function handlePrimitivesUpdate(message) {
      if (!_inBatch) {
        _logger.warn('Update received when not in batch');
        return;
      }
      _batchPrimitivesUpdate.push(message.data);
    }

    //-----------------------------------------------------------------------
    // Request senders

    function sendUpdateRequest(immediateResponse) {
      if (_awaitingImmediateUpdate) {
        // Already waiting for an immediate update - queue another one
        // Prevents the client from being flooded with update responses
        _immediateUpdateNextCycle = true;
        return;
      }

      if (immediateResponse) {
        _awaitingImmediateUpdate = true;
      }

      var updateMetadata = {
          portfolioViewport : {},
          primitiveViewport : {},
      }

      // Get the UI components to complete the metadata
      self.beforeUpdateRequested.fire(updateMetadata);

      // Send the request
      updateMetadata.immediateResponse = immediateResponse;
      _cometd.publish('/service/updates', updateMetadata);
    }

    function sendUpdateMode(gridName, rowId, colId, mode) {
      _cometd.publish('/service/updates/mode', {
        gridName: gridName,
        rowId: rowId,
        colId: colId,
        mode: mode
      });
    }

    //-----------------------------------------------------------------------
    // Public API

    this.changeView = function(viewName) {
      _logger.info("Sending initialize request");
      _portfolioDetails = null;
      _primitiveDetails = null;
      _changingView = true;
      _isRunning = false;

      _cometd.publish('/service/initialize', {
        viewName : viewName
      });
    }

    this.pause = function() {
      _cometd.publish('/service/currentview/pause', {});
    }

    this.resume = function() {
      _cometd.publish('/service/currentview/resume', {});
    }

    this.getViews = function() {
      _cometd.publish('/service/views', {});
    }

    this.triggerImmediateUpdate = function() {
      sendUpdateRequest(true);
    }

    this.startDetailedCellUpdates = function(gridName, rowId, colId) {
      sendUpdateMode(gridName, rowId, colId, "FULL");
    }

    this.stopDetailedCellUpdates = function(gridName, rowId, colId) {
      sendUpdateMode(gridName, rowId, colId, "SUMMARY");
    }

    this.connect = function() {
      _cometd.handshake();
    }

    this.disconnect = function() {
      _cometd.disconnect();
    }

    this.onConnected = new EventManager();
    this.onDisconnected = new EventManager();

    /**
     * Fired before a update is requested to allow UI components to contribute to the request, for example by inserting
     * viewport details. This way, multiple UI components can consume the same type of data while maintaining requests
     * for the minimum possible set of data.
     */
    this.beforeUpdateRequested = new EventManager();

    this.onViewListReceived = new EventManager();
    this.onViewInitialized = new EventManager();
    this.onStatusUpdateReceived = new EventManager();
    this.afterUpdateReceived = new EventManager();

    this.setPortfolioEventHandler = function(portfolioEventHandler) {
      _portfolioEventHandler = portfolioEventHandler;
    }

    this.setPrimitivesEventHandler = function(primitivesEventHandler) {
      _primitivesEventHandler = primitivesEventHandler;
    }

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

    init();
  }

  $.extend(true, window, {
      LiveResultsClient : LiveResultsClient
  });

}(jQuery));<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

const gulp = require('gulp');
const git = require('gulp-git');
const bump = require('gulp-bump');
const tagVersion = require('gulp-tag-version');
const config = require('../config.js');

/**
 * Update version in number in `package.json` file.
 *
 * @param {string} type The semver level identifier (`major`, `minor` or `patch`).
 * @return {WritableStream} The stream pipeline.
 */
function bumpVersion(type) {
  log.debug(`Bump version to next ${type} version`);
  return gulp.src([config.pkg, config.bower])
      .pipe(bump({type}))
      .pipe(gulp.dest(config.root));
}

/**
 * Commit the current changes:
 * - The `dist` directory containing final bundle.
 * - The `package.json` containing the new version number.
 *
 * @return {WritableStream} The stream pipeline.
 */
function performRelease() {
  log.debug('Perform release, commit current working directory');
  return gulp.src([config.pkg, config.bower, config.dest, config.readme])
      .pipe(git.add({args: '-f'}))
      .pipe(git.commit('release: release version'));
}

/**
 * Tag current version: the tag name will be extracted from
 * the `version` field in the `package.json` file.
 *
 * @return {WritableStream} The stream pipeline.
 */
function tagRelease() {
  log.debug('Tag release');
  return gulp.src(config.pkg).pipe(tagVersion());
}

/**
 * Prepare the next release cycle:
 * - Remove the `dist` directory containing bundle tagged on given version.
 * - Create a new commit preparing the next release.
 *
 * @return {WritableStream} The stream pipeline.
 */
function prepareNextRelease() {
  log.debug('Prepare repository for next release');
  return gulp.src(config.dest)
      .pipe(git.rm({args: '-r'}))
      .pipe(git.commit('release: prepare next release'));
}

/**
 * Create the release task for a given semver identifier.
 *
 * @param {string} type The semver level identifier (`major`, `minor` or `patch`).
 * @return {function} The task function.
 */
function createReleaseTask(type) {
  /**
   * Prepare the release: this is a just a wrapper around the `bumpVersion`
   * function with a pre-defined parameter.
   *
   * @return {WritableStream} The stream pipeline.
   */
  function prepareRelease() {
    return bumpVersion(type);
  }

  return gulp.series(
      prepareRelease,
      performRelease,
      tagRelease,
      prepareNextRelease
  );
};

module.exports = {
  patch: createReleaseTask('patch'),
  minor: createReleaseTask('minor'),
  major: createReleaseTask('major'),
};
<commit_msg>fix: fix release task<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

const gulp = require('gulp');
const git = require('gulp-git');
const bump = require('gulp-bump');
const tagVersion = require('gulp-tag-version');
const log = require('../log');
const config = require('../config.js');

/**
 * Update version in number in `package.json` file.
 *
 * @param {string} type The semver level identifier (`major`, `minor` or `patch`).
 * @return {WritableStream} The stream pipeline.
 */
function bumpVersion(type) {
  log.debug(`Bump version to next ${type} version`);
  return gulp.src([config.pkg, config.bower])
      .pipe(bump({type}))
      .pipe(gulp.dest(config.root));
}

/**
 * Commit the current changes:
 * - The `dist` directory containing final bundle.
 * - The `package.json` containing the new version number.
 *
 * @return {WritableStream} The stream pipeline.
 */
function performRelease() {
  log.debug('Perform release, commit current working directory');
  return gulp.src([config.pkg, config.bower, config.dest, config.readme])
      .pipe(git.add({args: '-f'}))
      .pipe(git.commit('release: release version'));
}

/**
 * Tag current version: the tag name will be extracted from
 * the `version` field in the `package.json` file.
 *
 * @return {WritableStream} The stream pipeline.
 */
function tagRelease() {
  log.debug('Tag release');
  return gulp.src(config.pkg).pipe(tagVersion());
}

/**
 * Prepare the next release cycle:
 * - Remove the `dist` directory containing bundle tagged on given version.
 * - Create a new commit preparing the next release.
 *
 * @return {WritableStream} The stream pipeline.
 */
function prepareNextRelease() {
  log.debug('Prepare repository for next release');
  return gulp.src(config.dest)
      .pipe(git.rm({args: '-r'}))
      .pipe(git.commit('release: prepare next release'));
}

/**
 * Create the release task for a given semver identifier.
 *
 * @param {string} type The semver level identifier (`major`, `minor` or `patch`).
 * @return {function} The task function.
 */
function createReleaseTask(type) {
  /**
   * Prepare the release: this is a just a wrapper around the `bumpVersion`
   * function with a pre-defined parameter.
   *
   * @return {WritableStream} The stream pipeline.
   */
  function prepareRelease() {
    return bumpVersion(type);
  }

  return gulp.series(
      prepareRelease,
      performRelease,
      tagRelease,
      prepareNextRelease
  );
};

module.exports = {
  patch: createReleaseTask('patch'),
  minor: createReleaseTask('minor'),
  major: createReleaseTask('major'),
};
<|endoftext|>


<commit_before>/** Data source that download static parking data */

var extraction = require('../infoExtraction/parkingInfoExtractor.js');
var verifier = require('../infoExtraction/parkingAllowedVerifier.js');
var geometryCalculator = require('../signGeometry/geometryCalculator.js');
var fs = require('fs');
var kml_parser = require('../lib/kml_parser.js');

function getURL() {
  return "http://donnees.ville.quebec.qc.ca/Handler.ashx?id=7&f=KML";
}

function cleanData(rawDataPath, finalDataPath, callback) {
  kml_parser.transformKML(rawDataPath, finalDataPath, function () {
    var result = JSON.parse(fs.readFileSync(finalDataPath));

    var pointsArray = result['features'];
    var i = 0;
    for (var data in pointsArray) {
      var value = pointsArray[i];
      var properties = value["properties"];
      var description = properties["TYPE_DESC"];

      try {
        properties["parsed_parking_value"] = extraction.getParkingInfo(description);
      }
      catch (err) {
        console.log("Could not parse description : " + description);
      }
      pointsArray[i] = value;
      i++
    }

    fs.writeFile(finalDataPath, JSON.stringify(result), "utf8", function () {
      callback();
    });
  });
}

function placeSignsOnStreets(parkingData, streetIdMap) {
  var parkings = parkingData['features'];

  for (var i = 0; i < parkings.length; i++) {
	 var parking = parkings[i];
	 var streetCoords = streetIdMap[parking.properties.ID_VOIE_PUB];
   if (streetCoords != undefined){
        var segment = geometryCalculator.findClosestSegment(parking.geometry.coordinates, streetCoords);
        parking.geometry.coordinates=geometryCalculator.projectPointOnLine(parking.geometry.coordinates, segment);
	      parking.properties.streetCoordinates=segment;
    }
  }
  return parkingData;
}

function validElementsFromCenter(pointsArray, polygon, extension) {
  var validData = [];

  var len = pointsArray.length;
  while (len--) {
    var feature = pointsArray[len];
    var point = feature['geometry'];
    var coordinates = point.coordinates;

    var lat = coordinates[1];
    if (lat > polygon.min_lat && lat < polygon.max_lat) {
      var lng = coordinates[0];

      if (lng > polygon.min_lng && lng < polygon.max_lng &&
          extension(feature)) {

          validData.push(feature);
      }
    }
  }

  return validData;
}

function responseExtension(value) {
  var properties = value["properties"];
  var stationnementValue = properties["parsed_parking_value"];

  properties["parking_allowed"] = verifier.isItPossibleToParkAtThisTime(new Date(), stationnementValue, 'none');

  if (properties["parking_allowed"]){
    return value;
  }
  return undefined;
}

module.exports.getURL = getURL;
module.exports.cleanData = cleanData;
module.exports.validElementsFromCenter = validElementsFromCenter;
module.exports.placeSignsOnStreets = placeSignsOnStreets;
module.exports.responseExtension = responseExtension;
<commit_msg>Add some exception handeling<commit_after>/** Data source that download static parking data */

var extraction = require('../infoExtraction/parkingInfoExtractor.js');
var verifier = require('../infoExtraction/parkingAllowedVerifier.js');
var geometryCalculator = require('../signGeometry/geometryCalculator.js');
var fs = require('fs');
var kml_parser = require('../lib/kml_parser.js');

function getURL() {
  return "http://donnees.ville.quebec.qc.ca/Handler.ashx?id=7&f=KML";
}

function cleanData(rawDataPath, finalDataPath, callback) {
  kml_parser.transformKML(rawDataPath, finalDataPath, function () {
    var result = JSON.parse(fs.readFileSync(finalDataPath));

    var pointsArray = result['features'];
    var i = 0;
    for (var data in pointsArray) {
      var value = pointsArray[i];
      var properties = value["properties"];
      var description = properties["TYPE_DESC"];

      try {
        properties["parsed_parking_value"] = extraction.getParkingInfo(description);
      }
      catch (err) {
        console.log("Could not parse description : " + description);
      }
      pointsArray[i] = value;
      i++
    }

    fs.writeFile(finalDataPath, JSON.stringify(result), "utf8", function () {
      callback();
    });
  });
}

function placeSignsOnStreets(parkingData, streetIdMap) {
  var parkings = parkingData['features'];

  for (var i = 0; i < parkings.length; i++) {
	 var parking = parkings[i];
	 var streetCoords = streetIdMap[parking.properties.ID_VOIE_PUB];
   if (streetCoords != undefined) {
     try {
       var segment = geometryCalculator.findClosestSegment(parking.geometry.coordinates, streetCoords);
       parking.geometry.coordinates=geometryCalculator.projectPointOnLine(parking.geometry.coordinates, segment);
       parking.properties.streetCoordinates=segment;
     }
     catch (err) {
       console.log("Could not place sign on street with parking : " + parking);
     }
    }
  }
  return parkingData;
}

function validElementsFromCenter(pointsArray, polygon, extension) {
  var validData = [];

  var len = pointsArray.length;
  while (len--) {
    var feature = pointsArray[len];
    var point = feature['geometry'];
    var coordinates = point.coordinates;

    var lat = coordinates[1];
    if (lat > polygon.min_lat && lat < polygon.max_lat) {
      var lng = coordinates[0];

      if (lng > polygon.min_lng && lng < polygon.max_lng &&
          extension(feature)) {

          validData.push(feature);
      }
    }
  }

  return validData;
}

function responseExtension(value) {
  var properties = value["properties"];
  var stationnementValue = properties["parsed_parking_value"];

  try {
    properties["parking_allowed"] = verifier.isItPossibleToParkAtThisTime(new Date(), stationnementValue, 'none');
  }
  catch (err) {
    console.log("Could not tell if parking is allowed : " + stationnementValue);
  }

  if (properties["parking_allowed"]){
    return true;
  }
  return undefined;
}

module.exports.getURL = getURL;
module.exports.cleanData = cleanData;
module.exports.validElementsFromCenter = validElementsFromCenter;
module.exports.placeSignsOnStreets = placeSignsOnStreets;
module.exports.responseExtension = responseExtension;
<|endoftext|>


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

    var directives = angular.module('redash.directives', []);

    directives.directive('rdTab', function() {
        return {
            restrict: 'E',
            scope: {
                'tabId': '@',
                'name': '@'
            },
            transclude: true,
            template: '
{{name}}
',
            replace: true,
            link: function(scope) {
                scope.$watch(function(){return scope.$parent.selectedTab}, function(tab) {
                    scope.selectedTab = tab;
                });
            }
        }
    });

    directives.directive('rdTabs', ['$location', function($location) {
        return {
            restrict: 'E',
            scope: {
                tabsCollection: '=',
                selectedTab: '='
            },
            template: '

{{tab.name}}

',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.selectTab = function(tabKey) {
                    $scope.selectedTab  = _.find($scope.tabsCollection, function(tab) { return tab.key == tabKey; });
                }

                $scope.$watch(function() { return $location.hash()}, function(hash) {
                    if (hash) {
                        $scope.selectTab($location.hash());
                    } else {
                        $scope.selectTab($scope.tabsCollection[0].key);
                    }
                });
            }
        }
    }]);

    directives.directive('editDashboardForm', ['$http', '$location', '$timeout', 'Dashboard', function($http, $location, $timeout, Dashboard) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/edit_dashboard.html',
            replace: true,
            link: function($scope, element, attrs) {
                var gridster = element.find(".gridster ul").gridster({
                    widget_margins: [5, 5],
                    widget_base_dimensions: [260, 100],
                    min_cols: 2,
                    max_cols: 2,
                    serialize_params: function($w, wgd) {
                        return {
                            col: wgd.col,
                            row: wgd.row,
                            id: $w.data('widget-id')
                        }
                    }
                }).data('gridster');

                var gsItemTemplate = '
' +
                                 '
{name}' +
                                 '

';

                $scope.$watch('dashboard.widgets', function(widgets) {
                    $timeout(function () {
                        gridster.remove_all_widgets();

                        if (widgets && widgets.length) {
                            var layout = [];

                            _.each(widgets, function(row, rowIndex) {
                                _.each(row, function(widget, colIndex) {
                                    layout.push({
                                        id: widget.id,
                                        col: colIndex+1,
                                        row: rowIndex+1,
                                        ySize: 1,
                                        xSize: widget.width,
                                        name: widget.visualization.query.name
                                    });
                                });
                            });

                            _.each(layout, function(item) {
                                var el = gsItemTemplate.replace('{id}', item.id).replace('{name}', item.name);
                                gridster.add_widget(el, item.xSize, item.ySize, item.col, item.row);

                            });
                        }
                    });
                }, true);

                $scope.saveDashboard = function() {
                    $scope.saveInProgress = true;
                    // TODO: we should use the dashboard service here.
                    if ($scope.dashboard.id) {
                        var positions = $(element).find('.gridster ul').data('gridster').serialize();
                        var layout = [];
                        _.each(_.sortBy(positions, function (pos) {
                            return pos.row * 10 + pos.col;
                        }), function (pos) {
                            var row = pos.row - 1;
                            var col = pos.col - 1;
                            layout[row] = layout[row] || [];
                            if (col > 0 && layout[row][col - 1] == undefined) {
                                layout[row][col - 1] = pos.id;
                            } else {
                                layout[row][col] = pos.id;
                            }

                        });
                        $scope.dashboard.layout = layout;

                        layout = JSON.stringify(layout);
                        $http.post('/api/dashboards/' + $scope.dashboard.id, {'name': $scope.dashboard.name, 'layout': layout}).success(function(response) {
                            $scope.dashboard = new Dashboard(response);
                            $scope.saveInProgress = false;
                            $(element).modal('hide');
                        })
                    } else {
                        $http.post('/api/dashboards', {'name': $scope.dashboard.name}).success(function(response) {
                            $(element).modal('hide');
                            $location.path('/dashboard/' + response.slug).replace();
                        })
                    }
                }

            }
        }
    }]);

    directives.directive('newWidgetForm', ['$http', 'Query', function($http, Query) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/new_widget_form.html',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}];

                var reset = function() {
                    $scope.saveInProgress = false;
                    $scope.widgetSize = 1;
                    $scope.queryId = null;
                    $scope.selectedVis = null;
                    $scope.query = null;

                }

                reset();

                $scope.loadVisualizations = function() {
                    if (!$scope.queryId) {
                        return;
                    }

                    Query.get({
                        id: $scope.queryId
                    }, function(query) {
                        if (query) {
                            $scope.query = query;
                            if(query.visualizations.length) {
                                $scope.selectedVis = query.visualizations[0];
                            }
                        }
                    });
                };

                $scope.saveWidget = function() {
                    $scope.saveInProgress = true;

                    var widget = {
                        'visualization_id': $scope.selectedVis.id,
                        'dashboard_id': $scope.dashboard.id,
                        'options': {},
                        'width': $scope.widgetSize
                    }

                    $http.post('/api/widgets', widget).success(function(response) {
                        // update dashboard layout
                        $scope.dashboard.layout = response['layout'];
                        if (response['new_row']) {
                            $scope.dashboard.widgets.push([response['widget']]);
                        } else {
                            $scope.dashboard.widgets[$scope.dashboard.widgets.length-1].push(response['widget']);
                        }

                        // close the dialog
                        $('#add_query_dialog').modal('hide');
                        reset();
                    })
                }

            }
        }
    }])

    // From: http://jsfiddle.net/joshdmiller/NDFHg/
    directives.directive('editInPlace', function () {
        return {
            restrict: 'E',
            scope: {
                value: '=',
                ignoreBlanks: '=',
                editable: '=',
                done: '='
            },
            template: function(tElement, tAttrs) {
                var elType = tAttrs.editor || 'input';
                var placeholder = tAttrs.placeholder || 'Click to edit';
                return '' +
                       '' + placeholder + '' +
                       '<{elType} ng-model="value" class="rd-form-control"></{elType}>'.replace('{elType}', elType);
            },
            link: function ($scope, element, attrs) {
                // Let's get a reference to the input element, as we'll want to reference it.
                var inputElement = angular.element(element.children()[2]);

                // This directive should have a set class so we can style it.
                element.addClass('edit-in-place');

                // Initially, we're not editing.
                $scope.editing = false;

                // ng-click handler to activate edit-in-place
                $scope.edit = function () {
                    $scope.oldValue = $scope.value;

                    $scope.editing = true;

                    // We control display through a class on the directive itself. See the CSS.
                    element.addClass('active');

                    // And we must focus the element.
                    // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
                    // we have to reference the first element in the array.
                    inputElement[0].focus();
                };

                function save() {
                    if ($scope.editing) {
                        if ($scope.ignoreBlanks && _.isEmpty($scope.value)) {
                            $scope.value = $scope.oldValue;
                        }
                        $scope.editing = false;
                        element.removeClass('active');

                        if ($scope.value !== $scope.oldValue) {
                            $scope.done && $scope.done();
                        }
                    }
                }

                $(inputElement).keydown(function(e) {
                    // 'return' or 'enter' key pressed
                    // allow 'shift' to break lines
                    if (e.which === 13 && !e.shiftKey) {
                        save();
                    } else if (e.which === 27) {
                        $scope.value = $scope.oldValue;
                        $scope.$apply(function() {
                            $(inputElement[0]).blur();
                        });
                    }
                }).blur(function() {
                    save();
                });
            }
        };
    });

    // http://stackoverflow.com/a/17904092/1559840
    directives.directive('jsonText', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {
              function into(input) {
                return JSON.parse(input);
              }
              function out(data) {
                return JSON.stringify(data, undefined, 2);
              }
              ngModel.$parsers.push(into);
              ngModel.$formatters.push(out);

            }
        };
    });

    directives.directive('rdTimer', ['$timeout', function ($timeout) {
        return {
            restrict: 'E',
            scope: { timestamp: '=' },
            template: '{{currentTime}}',
            controller: ['$scope' ,function ($scope) {
                $scope.currentTime = "00:00:00";
                var currentTimeout = null;

                var updateTime = function() {
                    $scope.currentTime = moment(moment() - moment($scope.timestamp)).utc().format("HH:mm:ss")
                    currentTimeout = $timeout(updateTime, 1000);
                }

                var cancelTimer = function() {
                    if (currentTimeout) {
                        $timeout.cancel(currentTimeout);
                        currentTimeout = null;
                    }
                }

                updateTime();

                $scope.$on('$destroy', function () {
                    cancelTimer();
                });
            }]
        };
    }]);

    directives.directive('rdTimeAgo', function() {
        return {
            restrict: 'E',
            scope: {
                value: '='
            },
            template: '' +
                        '' +
                        '-' +
                      ''
        }
    });
})();
<commit_msg>Fix #141: prevent the timer directive call digest loop every second<commit_after>(function() {
    'use strict';

    var directives = angular.module('redash.directives', []);

    directives.directive('rdTab', function() {
        return {
            restrict: 'E',
            scope: {
                'tabId': '@',
                'name': '@'
            },
            transclude: true,
            template: '
{{name}}
',
            replace: true,
            link: function(scope) {
                scope.$watch(function(){return scope.$parent.selectedTab}, function(tab) {
                    scope.selectedTab = tab;
                });
            }
        }
    });

    directives.directive('rdTabs', ['$location', function($location) {
        return {
            restrict: 'E',
            scope: {
                tabsCollection: '=',
                selectedTab: '='
            },
            template: '

{{tab.name}}

',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.selectTab = function(tabKey) {
                    $scope.selectedTab  = _.find($scope.tabsCollection, function(tab) { return tab.key == tabKey; });
                }

                $scope.$watch(function() { return $location.hash()}, function(hash) {
                    if (hash) {
                        $scope.selectTab($location.hash());
                    } else {
                        $scope.selectTab($scope.tabsCollection[0].key);
                    }
                });
            }
        }
    }]);

    directives.directive('editDashboardForm', ['$http', '$location', '$timeout', 'Dashboard', function($http, $location, $timeout, Dashboard) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/edit_dashboard.html',
            replace: true,
            link: function($scope, element, attrs) {
                var gridster = element.find(".gridster ul").gridster({
                    widget_margins: [5, 5],
                    widget_base_dimensions: [260, 100],
                    min_cols: 2,
                    max_cols: 2,
                    serialize_params: function($w, wgd) {
                        return {
                            col: wgd.col,
                            row: wgd.row,
                            id: $w.data('widget-id')
                        }
                    }
                }).data('gridster');

                var gsItemTemplate = '
' +
                                 '
{name}' +
                                 '

';

                $scope.$watch('dashboard.widgets', function(widgets) {
                    $timeout(function () {
                        gridster.remove_all_widgets();

                        if (widgets && widgets.length) {
                            var layout = [];

                            _.each(widgets, function(row, rowIndex) {
                                _.each(row, function(widget, colIndex) {
                                    layout.push({
                                        id: widget.id,
                                        col: colIndex+1,
                                        row: rowIndex+1,
                                        ySize: 1,
                                        xSize: widget.width,
                                        name: widget.visualization.query.name
                                    });
                                });
                            });

                            _.each(layout, function(item) {
                                var el = gsItemTemplate.replace('{id}', item.id).replace('{name}', item.name);
                                gridster.add_widget(el, item.xSize, item.ySize, item.col, item.row);

                            });
                        }
                    });
                }, true);

                $scope.saveDashboard = function() {
                    $scope.saveInProgress = true;
                    // TODO: we should use the dashboard service here.
                    if ($scope.dashboard.id) {
                        var positions = $(element).find('.gridster ul').data('gridster').serialize();
                        var layout = [];
                        _.each(_.sortBy(positions, function (pos) {
                            return pos.row * 10 + pos.col;
                        }), function (pos) {
                            var row = pos.row - 1;
                            var col = pos.col - 1;
                            layout[row] = layout[row] || [];
                            if (col > 0 && layout[row][col - 1] == undefined) {
                                layout[row][col - 1] = pos.id;
                            } else {
                                layout[row][col] = pos.id;
                            }

                        });
                        $scope.dashboard.layout = layout;

                        layout = JSON.stringify(layout);
                        $http.post('/api/dashboards/' + $scope.dashboard.id, {'name': $scope.dashboard.name, 'layout': layout}).success(function(response) {
                            $scope.dashboard = new Dashboard(response);
                            $scope.saveInProgress = false;
                            $(element).modal('hide');
                        })
                    } else {
                        $http.post('/api/dashboards', {'name': $scope.dashboard.name}).success(function(response) {
                            $(element).modal('hide');
                            $location.path('/dashboard/' + response.slug).replace();
                        })
                    }
                }

            }
        }
    }]);

    directives.directive('newWidgetForm', ['$http', 'Query', function($http, Query) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/new_widget_form.html',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}];

                var reset = function() {
                    $scope.saveInProgress = false;
                    $scope.widgetSize = 1;
                    $scope.queryId = null;
                    $scope.selectedVis = null;
                    $scope.query = null;

                }

                reset();

                $scope.loadVisualizations = function() {
                    if (!$scope.queryId) {
                        return;
                    }

                    Query.get({
                        id: $scope.queryId
                    }, function(query) {
                        if (query) {
                            $scope.query = query;
                            if(query.visualizations.length) {
                                $scope.selectedVis = query.visualizations[0];
                            }
                        }
                    });
                };

                $scope.saveWidget = function() {
                    $scope.saveInProgress = true;

                    var widget = {
                        'visualization_id': $scope.selectedVis.id,
                        'dashboard_id': $scope.dashboard.id,
                        'options': {},
                        'width': $scope.widgetSize
                    }

                    $http.post('/api/widgets', widget).success(function(response) {
                        // update dashboard layout
                        $scope.dashboard.layout = response['layout'];
                        if (response['new_row']) {
                            $scope.dashboard.widgets.push([response['widget']]);
                        } else {
                            $scope.dashboard.widgets[$scope.dashboard.widgets.length-1].push(response['widget']);
                        }

                        // close the dialog
                        $('#add_query_dialog').modal('hide');
                        reset();
                    })
                }

            }
        }
    }])

    // From: http://jsfiddle.net/joshdmiller/NDFHg/
    directives.directive('editInPlace', function () {
        return {
            restrict: 'E',
            scope: {
                value: '=',
                ignoreBlanks: '=',
                editable: '=',
                done: '='
            },
            template: function(tElement, tAttrs) {
                var elType = tAttrs.editor || 'input';
                var placeholder = tAttrs.placeholder || 'Click to edit';
                return '' +
                       '' + placeholder + '' +
                       '<{elType} ng-model="value" class="rd-form-control"></{elType}>'.replace('{elType}', elType);
            },
            link: function ($scope, element, attrs) {
                // Let's get a reference to the input element, as we'll want to reference it.
                var inputElement = angular.element(element.children()[2]);

                // This directive should have a set class so we can style it.
                element.addClass('edit-in-place');

                // Initially, we're not editing.
                $scope.editing = false;

                // ng-click handler to activate edit-in-place
                $scope.edit = function () {
                    $scope.oldValue = $scope.value;

                    $scope.editing = true;

                    // We control display through a class on the directive itself. See the CSS.
                    element.addClass('active');

                    // And we must focus the element.
                    // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
                    // we have to reference the first element in the array.
                    inputElement[0].focus();
                };

                function save() {
                    if ($scope.editing) {
                        if ($scope.ignoreBlanks && _.isEmpty($scope.value)) {
                            $scope.value = $scope.oldValue;
                        }
                        $scope.editing = false;
                        element.removeClass('active');

                        if ($scope.value !== $scope.oldValue) {
                            $scope.done && $scope.done();
                        }
                    }
                }

                $(inputElement).keydown(function(e) {
                    // 'return' or 'enter' key pressed
                    // allow 'shift' to break lines
                    if (e.which === 13 && !e.shiftKey) {
                        save();
                    } else if (e.which === 27) {
                        $scope.value = $scope.oldValue;
                        $scope.$apply(function() {
                            $(inputElement[0]).blur();
                        });
                    }
                }).blur(function() {
                    save();
                });
            }
        };
    });

    // http://stackoverflow.com/a/17904092/1559840
    directives.directive('jsonText', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {
              function into(input) {
                return JSON.parse(input);
              }
              function out(data) {
                return JSON.stringify(data, undefined, 2);
              }
              ngModel.$parsers.push(into);
              ngModel.$formatters.push(out);

            }
        };
    });

    directives.directive('rdTimer', [function () {
        return {
            restrict: 'E',
            scope: { timestamp: '=' },
            template: '{{currentTime}}',
            controller: ['$scope' ,function ($scope) {
                $scope.currentTime = "00:00:00";

                // We're using setInterval directly instead of $timeout, to avoid using $apply, to
                // prevent the digest loop being run every second.
                var currentTimer = setInterval(function() {
                    $scope.currentTime = moment(moment() - moment($scope.timestamp)).utc().format("HH:mm:ss");
                    $scope.$digest();
                }, 1000);

                $scope.$on('$destroy', function () {
                    if (currentTimer) {
                        cancelInterval(currentTimer);
                        currentTimer = null;
                    }
                });
            }]
        };
    }]);

    directives.directive('rdTimeAgo', function() {
        return {
            restrict: 'E',
            scope: {
                value: '='
            },
            template: '' +
                        '' +
                        '-' +
                      ''
        }
    });
})();
<|endoftext|>


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

'use strict';

var fs = require('fs');
var rnpm = require('rnpm/src/config');
var xcode = require('xcode');

// The current working directory should be project root of the app that is linking Realm.
var config = rnpm.getProjectConfig();

if (config.ios) {
  var pbxproj = config.ios.pbxprojPath;
  var project = xcode.project(pbxproj).parseSync();
  var target = project.getFirstTarget().uuid;

  // Create a Frameworks group if necessary.
  if (!project.pbxGroupByName('Frameworks')) {
    var group = project.pbxCreateGroup('Frameworks', '""');
    var mainGroup = project.getFirstProject().firstProject.mainGroup;

    project.getPBXGroupByKey(mainGroup).children.push({
      value: group,
      comment: 'Frameworks',
    });
  }

  ['libz', 'libsqlite3'].forEach(function(name) {
    project.addFramework('usr/lib/' + name + '.tbd', {
      lastKnownFileType: 'sourcecode.text-based-dylib-definition',
      sourceTree: 'SDKROOT',
      target: target,
    });
  });

  ['SystemConfiguration', 'CFNetwork', 'Security'].forEach(function (name) {
    project.addFramework('/System/Library/Frameworks/' + name + '.framework', {
      sourceTree: 'SDKROOT',
      target: target,
    });
  });

  fs.writeFileSync(pbxproj, project.writeSync());
}<commit_msg>Update permissions of rnpm-postlink<commit_after>#!/usr/bin/env node

'use strict';

var fs = require('fs');
var rnpm = require('rnpm/src/config');
var xcode = require('xcode');

// The current working directory should be project root of the app that is linking Realm.
var config = rnpm.getProjectConfig();

if (config.ios) {
  var pbxproj = config.ios.pbxprojPath;
  var project = xcode.project(pbxproj).parseSync();
  var target = project.getFirstTarget().uuid;

  // Create a Frameworks group if necessary.
  if (!project.pbxGroupByName('Frameworks')) {
    var group = project.pbxCreateGroup('Frameworks', '""');
    var mainGroup = project.getFirstProject().firstProject.mainGroup;

    project.getPBXGroupByKey(mainGroup).children.push({
      value: group,
      comment: 'Frameworks',
    });
  }

  ['libz', 'libsqlite3'].forEach(function(name) {
    project.addFramework('usr/lib/' + name + '.tbd', {
      lastKnownFileType: 'sourcecode.text-based-dylib-definition',
      sourceTree: 'SDKROOT',
      target: target,
    });
  });

  ['SystemConfiguration', 'CFNetwork', 'Security'].forEach(function (name) {
    project.addFramework('/System/Library/Frameworks/' + name + '.framework', {
      sourceTree: 'SDKROOT',
      target: target,
    });
  });

  fs.writeFileSync(pbxproj, project.writeSync());
}<|endoftext|>


<commit_before>/** base namespace for all DOAJ-specific functions */
var doaj = {
    scrollPosition: 100,
    init : function() {
        // Use Feather icons
        feather.replace();

        // Responsive menu
        var openMenu = document.querySelector(".secondary-nav__menu-toggle");
        var nav = document.querySelector(".secondary-nav__menu");

        openMenu.addEventListener('click', function() {
            nav.classList.toggle("secondary-nav__menu-toggle--active");
        }, false);

        // On scroll, display back-to-top button & add class to header primary menu
        var topBtn = document.getElementById("top"),
            topNav = document.querySelector(".primary-nav");

        function displayOnScroll() {
            if (topBtn && topNav) {
                if (document.body.scrollTop > doaj.scrollPosition || document.documentElement.scrollTop > doaj.scrollPosition) {
                    topBtn.style.display = "flex";
                    topNav.classList.add("primary-nav--scrolled");
                } else {
                    topBtn.style.display = "none";
                    topNav.classList.remove("primary-nav--scrolled");
                }
            }
        }

        window.addEventListener("scroll", function() {
          displayOnScroll();
        });

        // Tabs
        jQuery (function($) {
            $("[role='tab']").click(function(e) {
                e.preventDefault();
                $(this).attr("aria-selected", "true");
                $(this).parent().siblings().children().attr("aria-selected", "false");
                var tabpanelShow = $(this).attr("href");
                $(tabpanelShow).attr("aria-hidden", "false");
                $(tabpanelShow).siblings().attr("aria-hidden", "true");
            });
        });

        // Close flash notifications
        jQuery(document).ready(function($) {
            $(".flash_close").on("click", function(event) {
                event.preventDefault();
                var container = $(this).parents(".flash_container");
                container.remove();
            });
        });

        doaj.bindMiniSearch();
    },

    bitlyShortener : function(query, success_callback, error_callback) {

        function callbackWrapper(data) {
            success_callback(data.url);
        }

        function errorHandler() {
            alert("Sorry, we're unable to generate short urls at this time");
            error_callback();
        }

        var page = window.location.protocol + '//' + window.location.host + window.location.pathname;

        $.ajax({
            type: "POST",
            contentType: "application/json",
            dataType: "jsonp",
            url: "/service/shorten",
            data : JSON.stringify({page: page, query: query}),
            success: callbackWrapper,
            error: errorHandler
        });
    },

    journal_toc_id : function(journal) {
        // if e-issn is available, use that
        // if not, but a p-issn is available, use that
        // if neither ISSN is available, use the internal ID
        var ids = journal.bibjson.identifier;
        var pissns = [];
        var eissns = [];
        if (ids) {
            for (var i = 0; i < ids.length; i++) {
                if (ids[i].type === "pissn") {
                    pissns.push(ids[i].id)
                } else if (ids[i].type === "eissn") {
                    eissns.push(ids[i].id)
                }
            }
        }

        var toc_id = undefined;
        if (eissns.length > 0) { toc_id = eissns[0]; }
        if (!toc_id && pissns.length > 0) { toc_id = pissns[0]; }
        if (!toc_id) { toc_id = journal.id; }

        return toc_id;
    },

    bindMiniSearch : function() {
        const namespace = "doaj-minisearch";
        const container = "." + namespace + "--container";
        $(container + " [name=content-type]").on("change", function() {
            let that = $(this);
            if (!that.is(":checked")) {
                return;
            }
            let fields = that.parents(container).find("[name=fields]");
            if (that.val() === "journals") {
                fields.html(`
                    <option value="all">In all fields</option>
                    <option value="title">Title</option>
                    <option value="issn">ISSN</option>
                    <option value="subject">Subject</option>
                    <option value="publisher">Publisher</option>
                `)
            } else {
                fields.html(`
                    <option value="all">In all fields</option>
                    <option value="title">Title</option>
                    <option value="abstract">Abstract</option>
                    <option value="subject">Subject</option>
                    <option value="author">Author</option>
                `)
            }
        });
    },

    monthmap : [
        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"
    ],

    licenceMap : {
        "CC BY" : ["/static/doaj/images/cc/by.png", "https://creativecommons.org/licenses/by/4.0/"],
        "CC BY-NC" : ["/static/doaj/images/cc/by-nc.png", "https://creativecommons.org/licenses/by-nc/4.0/"],
        "CC BY-NC-ND" : ["/static/doaj/images/cc/by-nc-nd.png", "https://creativecommons.org/licenses/by-nc-nd/4.0/"],
        "CC BY-NC-SA" : ["/static/doaj/images/cc/by-nc-sa.png", "https://creativecommons.org/licenses/by-nc-sa/4.0/"],
        "CC BY-ND" : ["/static/doaj/images/cc/by-nd.png", "https://creativecommons.org/licenses/by-nd/4.0/"],
        "CC BY-SA" : ["/static/doaj/images/cc/by-sa.png", "https://creativecommons.org/licenses/by-sa/4.0/"]
    },

    humanYearMonth : function(datestr) {
        var date = new Date(datestr);
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();

        if (isNaN(monthnum) || isNaN(year)) {
            return "";
        }

        return doaj.monthmap[monthnum] + " " + String(year);
    },

    humanDate : function(datestr) {
        var date = new Date(datestr);
        var dom = date.getUTCDate();
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();

        if (isNaN(monthnum) || isNaN(year) || isNaN(dom)) {
            return "";
        }

        return String(dom) + " " + doaj.monthmap[monthnum] + " " + String(year);
    },

    humanDateTime : function(datestr) {
        var date = new Date(datestr);
        var dom = date.getUTCDate();
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();
        var hour = date.getUTCHours();
        var minute = date.getUTCMinutes();

        if (isNaN(monthnum) || isNaN(year) || isNaN(dom) || isNaN(hour) || isNaN(minute)) {
            return "";
        }

        if (String(hour).length === 1) {
            hour = "0" + String(hour);
        }

        if (String(minute).length === 1) {
            minute = "0" + String(minute);
        }

        return String(dom) + " " + doaj.monthmap[monthnum] + " " + String(year) + " at " + String(hour) + ":" + String(minute);
    },

    iso_datetime2date : function(isodate_str) {
        /* >>> '2003-04-03T00:00:00Z'.substring(0,10)
         * "2003-04-03"
         */
        return isodate_str.substring(0,10);
    },

    iso_datetime2date_and_time : function(isodate_str) {
        /* >>> "2013-12-13T22:35:42Z".replace('T',' ').replace('Z','')
         * "2013-12-13 22:35:42"
         */
        if (!isodate_str) { return "" }
        return isodate_str.replace('T',' ').replace('Z','')
    },

    scroller : function(selector, notFirstTime, duration, callback) {
        if (!duration) {
            duration = 1
        }
        if (notFirstTime === undefined) {
            notFirstTime = true;
        }

        if (doaj.scroller.hasOwnProperty("doScroll")) {
            $("html, body").animate(
                {
                    scrollTop: $(selector).offset().top
                },
                {
                    duration: duration,
                    always: callback
                }
            );
        } else {
            doaj.scroller.doScroll = true;
        }
    }
};

function setCookieConsent(event) {
    event.preventDefault();
    $.ajax({
        type: "GET",
        url: "/cookie_consent",
        success: function() {
            $("#cookie-consent").remove();
        },
        error : function() {
            alert("We weren't able to set your cookie consent preferences, please try again later.");
        }
    })
}

function dissmissSiteNote(event) {
    event.preventDefault();
    $.ajax({
        type: "GET",
        url: "/dismiss_site_note",
        success: function() {
            $("#site-note").remove();
        },
        error : function() {
            alert("Something went wrong, we weren't able to dismiss this note. Please try again later.");
        }
    })
}
<commit_msg>add check before binding event listener, as menu options may not be available depending on context<commit_after>/** base namespace for all DOAJ-specific functions */
var doaj = {
    scrollPosition: 100,
    init : function() {
        // Use Feather icons
        feather.replace();

        // Responsive menu
        var openMenu = document.querySelector(".secondary-nav__menu-toggle");
        var nav = document.querySelector(".secondary-nav__menu");

        if (openMenu) {
            openMenu.addEventListener('click', function () {
                nav.classList.toggle("secondary-nav__menu-toggle--active");
            }, false);
        }

        // On scroll, display back-to-top button & add class to header primary menu
        var topBtn = document.getElementById("top"),
            topNav = document.querySelector(".primary-nav");

        function displayOnScroll() {
            if (topBtn && topNav) {
                if (document.body.scrollTop > doaj.scrollPosition || document.documentElement.scrollTop > doaj.scrollPosition) {
                    topBtn.style.display = "flex";
                    topNav.classList.add("primary-nav--scrolled");
                } else {
                    topBtn.style.display = "none";
                    topNav.classList.remove("primary-nav--scrolled");
                }
            }
        }

        window.addEventListener("scroll", function() {
          displayOnScroll();
        });

        // Tabs
        jQuery (function($) {
            $("[role='tab']").click(function(e) {
                e.preventDefault();
                $(this).attr("aria-selected", "true");
                $(this).parent().siblings().children().attr("aria-selected", "false");
                var tabpanelShow = $(this).attr("href");
                $(tabpanelShow).attr("aria-hidden", "false");
                $(tabpanelShow).siblings().attr("aria-hidden", "true");
            });
        });

        // Close flash notifications
        jQuery(document).ready(function($) {
            $(".flash_close").on("click", function(event) {
                event.preventDefault();
                var container = $(this).parents(".flash_container");
                container.remove();
            });
        });

        doaj.bindMiniSearch();
    },

    bitlyShortener : function(query, success_callback, error_callback) {

        function callbackWrapper(data) {
            success_callback(data.url);
        }

        function errorHandler() {
            alert("Sorry, we're unable to generate short urls at this time");
            error_callback();
        }

        var page = window.location.protocol + '//' + window.location.host + window.location.pathname;

        $.ajax({
            type: "POST",
            contentType: "application/json",
            dataType: "jsonp",
            url: "/service/shorten",
            data : JSON.stringify({page: page, query: query}),
            success: callbackWrapper,
            error: errorHandler
        });
    },

    journal_toc_id : function(journal) {
        // if e-issn is available, use that
        // if not, but a p-issn is available, use that
        // if neither ISSN is available, use the internal ID
        var ids = journal.bibjson.identifier;
        var pissns = [];
        var eissns = [];
        if (ids) {
            for (var i = 0; i < ids.length; i++) {
                if (ids[i].type === "pissn") {
                    pissns.push(ids[i].id)
                } else if (ids[i].type === "eissn") {
                    eissns.push(ids[i].id)
                }
            }
        }

        var toc_id = undefined;
        if (eissns.length > 0) { toc_id = eissns[0]; }
        if (!toc_id && pissns.length > 0) { toc_id = pissns[0]; }
        if (!toc_id) { toc_id = journal.id; }

        return toc_id;
    },

    bindMiniSearch : function() {
        const namespace = "doaj-minisearch";
        const container = "." + namespace + "--container";
        $(container + " [name=content-type]").on("change", function() {
            let that = $(this);
            if (!that.is(":checked")) {
                return;
            }
            let fields = that.parents(container).find("[name=fields]");
            if (that.val() === "journals") {
                fields.html(`
                    <option value="all">In all fields</option>
                    <option value="title">Title</option>
                    <option value="issn">ISSN</option>
                    <option value="subject">Subject</option>
                    <option value="publisher">Publisher</option>
                `)
            } else {
                fields.html(`
                    <option value="all">In all fields</option>
                    <option value="title">Title</option>
                    <option value="abstract">Abstract</option>
                    <option value="subject">Subject</option>
                    <option value="author">Author</option>
                `)
            }
        });
    },

    monthmap : [
        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"
    ],

    licenceMap : {
        "CC BY" : ["/static/doaj/images/cc/by.png", "https://creativecommons.org/licenses/by/4.0/"],
        "CC BY-NC" : ["/static/doaj/images/cc/by-nc.png", "https://creativecommons.org/licenses/by-nc/4.0/"],
        "CC BY-NC-ND" : ["/static/doaj/images/cc/by-nc-nd.png", "https://creativecommons.org/licenses/by-nc-nd/4.0/"],
        "CC BY-NC-SA" : ["/static/doaj/images/cc/by-nc-sa.png", "https://creativecommons.org/licenses/by-nc-sa/4.0/"],
        "CC BY-ND" : ["/static/doaj/images/cc/by-nd.png", "https://creativecommons.org/licenses/by-nd/4.0/"],
        "CC BY-SA" : ["/static/doaj/images/cc/by-sa.png", "https://creativecommons.org/licenses/by-sa/4.0/"]
    },

    humanYearMonth : function(datestr) {
        var date = new Date(datestr);
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();

        if (isNaN(monthnum) || isNaN(year)) {
            return "";
        }

        return doaj.monthmap[monthnum] + " " + String(year);
    },

    humanDate : function(datestr) {
        var date = new Date(datestr);
        var dom = date.getUTCDate();
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();

        if (isNaN(monthnum) || isNaN(year) || isNaN(dom)) {
            return "";
        }

        return String(dom) + " " + doaj.monthmap[monthnum] + " " + String(year);
    },

    humanDateTime : function(datestr) {
        var date = new Date(datestr);
        var dom = date.getUTCDate();
        var monthnum = date.getUTCMonth();
        var year = date.getUTCFullYear();
        var hour = date.getUTCHours();
        var minute = date.getUTCMinutes();

        if (isNaN(monthnum) || isNaN(year) || isNaN(dom) || isNaN(hour) || isNaN(minute)) {
            return "";
        }

        if (String(hour).length === 1) {
            hour = "0" + String(hour);
        }

        if (String(minute).length === 1) {
            minute = "0" + String(minute);
        }

        return String(dom) + " " + doaj.monthmap[monthnum] + " " + String(year) + " at " + String(hour) + ":" + String(minute);
    },

    iso_datetime2date : function(isodate_str) {
        /* >>> '2003-04-03T00:00:00Z'.substring(0,10)
         * "2003-04-03"
         */
        return isodate_str.substring(0,10);
    },

    iso_datetime2date_and_time : function(isodate_str) {
        /* >>> "2013-12-13T22:35:42Z".replace('T',' ').replace('Z','')
         * "2013-12-13 22:35:42"
         */
        if (!isodate_str) { return "" }
        return isodate_str.replace('T',' ').replace('Z','')
    },

    scroller : function(selector, notFirstTime, duration, callback) {
        if (!duration) {
            duration = 1
        }
        if (notFirstTime === undefined) {
            notFirstTime = true;
        }

        if (doaj.scroller.hasOwnProperty("doScroll")) {
            $("html, body").animate(
                {
                    scrollTop: $(selector).offset().top
                },
                {
                    duration: duration,
                    always: callback
                }
            );
        } else {
            doaj.scroller.doScroll = true;
        }
    }
};

function setCookieConsent(event) {
    event.preventDefault();
    $.ajax({
        type: "GET",
        url: "/cookie_consent",
        success: function() {
            $("#cookie-consent").remove();
        },
        error : function() {
            alert("We weren't able to set your cookie consent preferences, please try again later.");
        }
    })
}

function dissmissSiteNote(event) {
    event.preventDefault();
    $.ajax({
        type: "GET",
        url: "/dismiss_site_note",
        success: function() {
            $("#site-note").remove();
        },
        error : function() {
            alert("Something went wrong, we weren't able to dismiss this note. Please try again later.");
        }
    })
}
<|endoftext|>


<commit_before>describe("About Functions", function () {

  describe("Default Parameters", function () {

    it("should understand default parameters basic usage", function () {

      function greeting(string = 'party') {
        return 'Welcome to the ' + string + ' pal!';
      }

      expect(greeting()).toEqual(FILL_ME_IN);
      expect(greeting('get together')).toEqual(FILL_ME_IN);
      expect(undefined).toEqual(FILL_ME_IN);
      expect(null).toEqual(FILL_ME_IN);

      function getDefaultValue() {
        return 'party';
      }

      function greetingAgain(string = getDefaultValue()) {
        return 'Welcome to the ' + string + ' pal!';
      }

      expect(greetingAgain()).toEqual(FILL_ME_IN);
    });
  });

  // describe('Rest Paramaters', function() {
  //
  // })
  //
  // describe('Spread Parameters', function() {
  //
  // })
  //
  describe('Arrow Functions', function() {

    it('shound understand syntax', function() {

      var arrowFn = string => string;
      expect(typeof arrowFn).toEqual(FILL_ME_IN)
      expect(comparator instanceof Function).toEqual(FILL_ME_IN);

      expect(arrowFn('hello')).toEqual(FILL_ME_IN);

      var arrowFnTwo = (number) => number * 2;
      expect(arrowFnTwo(4)).toEqual(FILL_ME_IN);

      var arrowFnThree = () => 1337;
      expect(arrowFnThree(4)).toEqual(FILL_ME_IN);

      var arrowFnFour = () => ({  id: 1337 });
      expect(typeof arrowFnFour()).toEqual(FILL_ME_IN);
      expect(arrowFnFour()).toEqual(FILL_ME_IN);

      var arrowFnFive = ((number) => { 'there are ' + number + ' days in a week'; })(7);
      expect(arrowFnFive).toEqual(FILL_ME_IN);

      // Concise array operations
      // var values = [1, 6, 7, 2, 6];
      // var sortedArray = values.sort((a, b) => a - b);
    })

  })
});
<commit_msg>feat: Add rest parameters test examples<commit_after>describe("About Functions", function () {

  describe("Default Parameters", function () {

    it("should understand default parameters basic usage", function () {

      function greeting(string = 'party') {
        return 'Welcome to the ' + string + ' pal!';
      }

      expect(greeting()).toEqual(FILL_ME_IN);
      expect(greeting('get together')).toEqual(FILL_ME_IN);
      expect(undefined).toEqual(FILL_ME_IN);
      expect(null).toEqual(FILL_ME_IN);

      function getDefaultValue() {
        return 'party';
      }

      function greetingAgain(string = getDefaultValue()) {
        return 'Welcome to the ' + string + ' pal!';
      }

      expect(greetingAgain()).toEqual(FILL_ME_IN);
    });
  });

  describe('Rest Paramaters', function() {

    it('should understand populate function parameters', function() {

      var setPersonName = function(firstName, lastName, ...middleNames) {
        return {
          middleNames: middleNames;
        }
      }

      var author = setPersonName('Arthur', 'Clarke', 'C');

      //Array
      expect(typeof author.middleNames).toEqual(FILL_ME_IN);
      expect(author.middleNames.length).toEqual(FILL_ME_IN);
      expect(author.middleNames[0]).toEqual(FILL_ME_IN);
    })

  })

  // describe('Spread Parameters', function() {
  //
  // })

  describe('Arrow Functions', function() {

    it('shound understand syntax', function() {

      var arrowFn = string => string;
      expect(typeof arrowFn).toEqual(FILL_ME_IN)
      expect(comparator instanceof Function).toEqual(FILL_ME_IN);

      expect(arrowFn('hello')).toEqual(FILL_ME_IN);

      var arrowFnTwo = (number) => number * 2;
      expect(arrowFnTwo(4)).toEqual(FILL_ME_IN);

      var arrowFnThree = () => 1337;
      expect(arrowFnThree(4)).toEqual(FILL_ME_IN);

      var arrowFnFour = () => ({  id: 1337 });
      expect(typeof arrowFnFour()).toEqual(FILL_ME_IN);
      expect(arrowFnFour()).toEqual(FILL_ME_IN);

      var arrowFnFive = ((number) => { 'there are ' + number + ' days in a week'; })(7);
      expect(arrowFnFive).toEqual(FILL_ME_IN);

      // Concise array operations
      // var values = [1, 6, 7, 2, 6];
      // var sortedArray = values.sort((a, b) => a - b);
    })

  })
});
<|endoftext|>