<commit_before>/**
 * A JavaScript API for transmitting and verifying Credentials.
 *
 * @author Dave Longley
 *
 * Copyright (c) 2015 Digital Bazaar, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of Digital Bazaar, Inc. nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
var _ = require('lodash');
var async = require('async');
var request = require('request');
var libs = {};

// module API
var api = {};
module.exports = api;

// constants
var IDENTITY_CONTEXT_URL = 'https://w3id.org/identity/v1';
var IDENTITY_FRAME = {
  '@context': IDENTITY_CONTEXT_URL,
  type: 'Identity'
};

/**
 * Allows injectables to be set or retrieved.
 *
 * @param name the name of the injectable to use (
 *          eg: `jsonld`, `jsonld-signatures`).
 * @param [injectable] the api to set for the injectable, only present for setter,
 *          omit for getter.
 * @param [options] the options to use:
 *          [configure] by default, this library will auto-configure certain
 *            passed injectables (eg: jsonld) to enable features like DID-based
 *            URL resolution; to disable this feature, set `configure` to false.
 *
 * @return the API for `name` if not using this method as a setter, otherwise
 *   undefined.
 */
api.use = function(name, injectable, options) {
  options = options || {};

  // initialize lib entry
  if(!libs[name]) {
    libs[name] = {
      api: null,
      // if `options.configure` is false, set lib as already configured
      // otherwise set as unconfigured and configure on first use later
      configured: ('configure' in options ? !options.configure : false)
    };
  }

  // setter mode
  if(injectable) {
    libs[name].api = injectable;
    return;
  }

  // getter mode:

  // api not yet set, load default
  if(!libs[name].api) {
    libs[name].api = require(name);
    if(name === 'jsonld') {
      // locally configure jsonld
      // Note: this configuration is necessary as a basic setup of `jsonld`
      // in a secure mode, it is not the same as later configuration required
      // for use by this library
      libs[name].api = libs[name].api();
      libs[name].api.useDocumentLoader('node', {secure: true, strictSSL: true});
    }
  }

  // ensure api is configured before returning it
  if(!libs[name].configured) {
    // mark library as configured immediately to avoid circular dependency
    // issues
    libs[name].configured = true;
    if(name === 'did-io' || name === 'jsonld-signatures') {
      libs[name].api.use('jsonld', api.use('jsonld'));
      if(name === 'did-io') {
        libs[name].api.use('jsonld-signatures', api.use('jsonld-signatures'));
      }
    } else if(name === 'jsonld') {
      // wrap document loader w/DID-based loader
      libs[name].api.documentLoader = api.use('did-io').createDocumentLoader({
        wrap: libs[name].api.documentLoader
      });
    }
  }
  return libs[name].api;
};

/**
 * Verifies the digital signature on the given Identity object and any
 * credentials it contains. This call only checks authenticity, it does not
 * check a trust store for the identities used to sign.
 *
 * TODO: This call should accept a function for checking trusted identities,
 * domains, etc., so these things can be checked prior to normalization.
 *
 * The callback will be passed the following object:
 *
 * {
 *   verified: <true/false>,
 *   identity: <framed identity>,
 *   domain: <domain the signature was signed for>,
 *   publicKey: <public key object for the creator of the signature>,
 *   publicKeyOwner: <identity object for the creator of the signature>,
 *   // a map of verified objects for each credential (ID => verified)
 *   credentials: {}
 * }
 *
 * @param identity the identity to check.
 * @param options the options to use:
 *          [checkTimestamp]: check signature timestamp (default: true) on
 *            the main Identity credential.
 *          [maxTimestampDelta]: signature must be created within a window of
 *            this many seconds (default: 15 minutes).
 *          [documentLoader(url, callback(err, remoteDoc))] the document loader.
 * @param callback(err, result) called once the operation completes.
 */
api.verify = function(identity, options, callback) {
  if(typeof options === 'function') {
    callback = options;
    options = {};
  }
  options = options || {};

  var jsonld = api.use('jsonld');
  var jsigs = api.use('jsonld-signatures');

  // TODO: assume identity is already properly framed prior to consumption;
  // this is a temporary requirement until jsonld.js supports named graph
  // framing

  // TODO: move any of opencred-verifier code here?
  var result = {
    credentials: {}
  };

  async.auto({
    frame: function(callback) {
      return callback(null, identity);
      /*
      jsonld.frame(
        identity, IDENTITY_FRAME, function(err, framed) {
          if(err) {
            return callback(err);
          }
          var id = framed['@graph'][0];
          if(!id) {
            return callback(new Error('Unknown Identity format.'));
          }
          id['@context'] = framed['@context'];
          callback(null, id);
        });*/
    },
    verifyIdentity: ['frame', function(callback, results) {
      result.identity = results.frame;
      var opts = _.assign({
        id: results.frame.id,
        checkTimestamp: true
      }, options, {
        checkDomain: checkDomain(result),
        checkKeyOwner: checkKeyOwner(result)
      });
      jsigs.verify(result.identity, opts, function(err, verified) {
        result.verified = verified;
        callback(err, result);
      });
    }],
    verifyCredentials: ['verifyIdentity', function(callback, results) {
      var credentials = jsonld.getValues(result.identity, 'credential');
      async.forEach(credentials, function(credential, callback) {
        credential = credential['@graph'];
        credential['@context'] = results.frame['@context'];
        var res = result.credentials[credential.id] = {};
        var opts = _.assign(options, {
          id: credential.id,
          checkDomain: checkDomain(res),
          checkKeyOwner: checkKeyOwner(res)
        });
        jsigs.verify(credential, opts, function(err, verified) {
          res.verified = verified;
          callback(err, res);
        });
      }, callback);
    }]
  }, function(err) {
    callback(err, result);
  });
};

api.send = function(options, callback) {
  var url = options.url;
  var credential = options.credential;
  var privateKeyPem = options.privateKeyPem;
  var publicKeyId = options.publicKeyId;

  var requestOptions = {
    url: url,
    body: credential,
    json: true,
    httpSignature: {
      key: privateKeyPem,
      keyId: publicKeyId,
      headers: ['date', 'host', 'request-line']
    }
  };

  request.post(requestOptions, callback);
};

// TODO: define a function for getting a public key via did-io

function checkDomain(result) {
  // TODO: check against some config value for the domain or similar
  return function(domain, options, callback) {
    result.domain = domain;
    return callback(null, true);
  };
}

function checkKeyOwner(result) {
  // TODO: check against a list of trusted owners, perhaps based on credential
  // type as well
  return function(owner, key, options, callback) {
    result.publicKey = key;
    result.publicKeyOwner = owner;
    return callback(null, true);
  };
}
<commit_msg>Add TODO.<commit_after>/**
 * A JavaScript API for transmitting and verifying Credentials.
 *
 * @author Dave Longley
 *
 * Copyright (c) 2015 Digital Bazaar, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of Digital Bazaar, Inc. nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
var _ = require('lodash');
var async = require('async');
var request = require('request');
var libs = {};

// module API
var api = {};
module.exports = api;

// constants
var IDENTITY_CONTEXT_URL = 'https://w3id.org/identity/v1';
var IDENTITY_FRAME = {
  '@context': IDENTITY_CONTEXT_URL,
  type: 'Identity'
};

/**
 * Allows injectables to be set or retrieved.
 *
 * @param name the name of the injectable to use (
 *          eg: `jsonld`, `jsonld-signatures`).
 * @param [injectable] the api to set for the injectable, only present for setter,
 *          omit for getter.
 * @param [options] the options to use:
 *          [configure] by default, this library will auto-configure certain
 *            passed injectables (eg: jsonld) to enable features like DID-based
 *            URL resolution; to disable this feature, set `configure` to false.
 *
 * @return the API for `name` if not using this method as a setter, otherwise
 *   undefined.
 */
api.use = function(name, injectable, options) {
  options = options || {};

  // initialize lib entry
  if(!libs[name]) {
    libs[name] = {
      api: null,
      // if `options.configure` is false, set lib as already configured
      // otherwise set as unconfigured and configure on first use later
      configured: ('configure' in options ? !options.configure : false)
    };
  }

  // setter mode
  if(injectable) {
    libs[name].api = injectable;
    return;
  }

  // getter mode:

  // api not yet set, load default
  if(!libs[name].api) {
    libs[name].api = require(name);
    if(name === 'jsonld') {
      // locally configure jsonld
      // Note: this configuration is necessary as a basic setup of `jsonld`
      // in a secure mode, it is not the same as later configuration required
      // for use by this library
      libs[name].api = libs[name].api();
      libs[name].api.useDocumentLoader('node', {secure: true, strictSSL: true});
    }
  }

  // ensure api is configured before returning it
  if(!libs[name].configured) {
    // mark library as configured immediately to avoid circular dependency
    // issues
    libs[name].configured = true;
    if(name === 'did-io' || name === 'jsonld-signatures') {
      libs[name].api.use('jsonld', api.use('jsonld'));
      if(name === 'did-io') {
        libs[name].api.use('jsonld-signatures', api.use('jsonld-signatures'));
      }
    } else if(name === 'jsonld') {
      // wrap document loader w/DID-based loader
      libs[name].api.documentLoader = api.use('did-io').createDocumentLoader({
        wrap: libs[name].api.documentLoader
      });
    }
  }
  return libs[name].api;
};

/**
 * Verifies the digital signature on the given Identity object and any
 * credentials it contains. This call only checks authenticity, it does not
 * check a trust store for the identities used to sign.
 *
 * TODO: This call should accept a function for checking trusted identities,
 * domains, etc., so these things can be checked prior to normalization.
 *
 * The callback will be passed the following object:
 *
 * {
 *   verified: <true/false>,
 *   identity: <framed identity>,
 *   domain: <domain the signature was signed for>,
 *   publicKey: <public key object for the creator of the signature>,
 *   publicKeyOwner: <identity object for the creator of the signature>,
 *   // a map of verified objects for each credential (ID => verified)
 *   credentials: {}
 * }
 *
 * @param identity the identity to check.
 * @param options the options to use:
 *          [checkTimestamp]: check signature timestamp (default: true) on
 *            the main Identity credential.
 *          [maxTimestampDelta]: signature must be created within a window of
 *            this many seconds (default: 15 minutes).
 *          [documentLoader(url, callback(err, remoteDoc))] the document loader.
 * @param callback(err, result) called once the operation completes.
 */
api.verify = function(identity, options, callback) {
  if(typeof options === 'function') {
    callback = options;
    options = {};
  }
  options = options || {};

  var jsonld = api.use('jsonld');
  var jsigs = api.use('jsonld-signatures');

  // TODO: assume identity is already properly framed prior to consumption;
  // this is a temporary requirement until jsonld.js supports named graph
  // framing

  // TODO: move any of opencred-verifier code here?
  var result = {
    credentials: {}
  };

  async.auto({
    frame: function(callback) {
      return callback(null, identity);
      /*
      jsonld.frame(
        identity, IDENTITY_FRAME, function(err, framed) {
          if(err) {
            return callback(err);
          }
          var id = framed['@graph'][0];
          if(!id) {
            return callback(new Error('Unknown Identity format.'));
          }
          id['@context'] = framed['@context'];
          callback(null, id);
        });*/
    },
    verifyIdentity: ['frame', function(callback, results) {
      // TODO: add checkKey function that will scan the list of credentials
      // for a public key credential if the creator URI is not a known scheme
      // ... then further check to see if the public key credential is signed
      // by the IdP for `identity.id`
      result.identity = results.frame;
      var opts = _.assign({
        id: results.frame.id,
        checkTimestamp: true
      }, options, {
        checkDomain: checkDomain(result),
        checkKeyOwner: checkKeyOwner(result)
      });
      jsigs.verify(result.identity, opts, function(err, verified) {
        result.verified = verified;
        callback(err, result);
      });
    }],
    verifyCredentials: ['verifyIdentity', function(callback, results) {
      var credentials = jsonld.getValues(result.identity, 'credential');
      async.forEach(credentials, function(credential, callback) {
        credential = credential['@graph'];
        credential['@context'] = results.frame['@context'];
        var res = result.credentials[credential.id] = {};
        var opts = _.assign(options, {
          id: credential.id,
          checkDomain: checkDomain(res),
          checkKeyOwner: checkKeyOwner(res)
        });
        jsigs.verify(credential, opts, function(err, verified) {
          res.verified = verified;
          callback(err, res);
        });
      }, callback);
    }]
  }, function(err) {
    callback(err, result);
  });
};

api.send = function(options, callback) {
  var url = options.url;
  var credential = options.credential;
  var privateKeyPem = options.privateKeyPem;
  var publicKeyId = options.publicKeyId;

  var requestOptions = {
    url: url,
    body: credential,
    json: true,
    httpSignature: {
      key: privateKeyPem,
      keyId: publicKeyId,
      headers: ['date', 'host', 'request-line']
    }
  };

  request.post(requestOptions, callback);
};

// TODO: define a function for getting a public key via did-io

function checkDomain(result) {
  // TODO: check against some config value for the domain or similar
  return function(domain, options, callback) {
    result.domain = domain;
    return callback(null, true);
  };
}

function checkKeyOwner(result) {
  // TODO: check against a list of trusted owners, perhaps based on credential
  // type as well
  return function(owner, key, options, callback) {
    result.publicKey = key;
    result.publicKeyOwner = owner;
    return callback(null, true);
  };
}
<|endoftext|>


<commit_before>// Purple side of the message channel for browser events
// Copyright 2011 Google Inc.
// see Purple/license.txt for BSD license
// johnjbarton@google.com

(function() {
  var thePurple = window.purple;
  var Assembly = thePurple.Assembly;
  var channel__ = new thePurple.PurplePart('channel');

  Assembly.addPartContainer(channel__);

  channel__.recv = function(message) {
    this.toSomeParts('recv', [message]);
  }

  thePurple.Browser = {};
  var Browser = thePurple.Browser;

  /*
   * In:
   * channel.protocolName: string recognized by browser proxy
   * channel.version: number possibly matched by browser proxy
   * channel.recv: function(message) called on each message
   * Out:
   * channel.send: function(message) callable
   */
  Browser.connect = function connectToBrowser(channel) {

    function recvPort(event) {
      console.log("channelByPostMessage.recvPort "+event.origin, event);
      if (event.data.indexOf(channel.protocolName) !== 0) {
        return; // not for us
      }
      window.removeEventListener('message', recvPort, false);
      if (event.ports && event.ports.length) {
        channel.port = event.ports[0];
        channel.port.onmessage = channel.recv.bind(channel);
        channel.send = function(message) { this.port.postMessage(message); };
      } else {
        // no MessageChannel support I guess.
        channel.onmessage = channel.recv.bind(channel);
        channel.source = event.source;
        channel.origin = event.origin;
        window.addEventListener('message', channel.onmessage, false);
        channel.send = function(message) {
          channel.source.postMessage(message, channel.origin);
        };
      }
      channel.features.push('channel');
    }

    function requestPort() {
      if (window.parent !== window) { // we are an iframe
        window.addEventListener('message', recvPort, false);
        window.parent.postMessage(channel.protocolName+' '+channel.version, "*"); // tell our parent we are loaded
        return true;
      } else {
        console.error("connectToBrowser must be included in an iframe");
        return false;
      }
    }

    return requestPort();
  };

  Browser.disconnect = function (channel) {
    if (channel.port) {
      channel.port.close();
    } else {
      window.removeEventListener('message', channel.onmessage, false);
    }
  };

  //---------------------------------------------------------------------------------------------
  // Implement PurplePart
  channel__.initialize = function() {
      this.protocolName ='IAmPurple';
      this.version = 1;
      console.log("Calling Browser.connect");
      Browser.connect(this);
  };

  channel__.destroy = function() {
      Browser.disconnect(this);
  };

  thePurple.registerPart(channel__);

}());
<commit_msg>We still need a type name in the new scheme<commit_after>// Purple side of the message channel for browser events
// Copyright 2011 Google Inc.
// see Purple/license.txt for BSD license
// johnjbarton@google.com

(function() {
  var thePurple = window.purple;
  var Assembly = thePurple.Assembly;
  var channel__ = new thePurple.PurplePart('channel');

  Assembly.addPartContainer(channel__);

  channel__.recv = function(message) {
    this.toSomeParts('recv', [message]);
  }

  thePurple.Browser = {};
  var Browser = thePurple.Browser;

  /*
   * In:
   * channel.protocolName: string recognized by browser proxy
   * channel.version: number possibly matched by browser proxy
   * channel.recv: function(message) called on each message
   * Out:
   * channel.send: function(message) callable
   */
  Browser.connect = function connectToBrowser(channel) {

    function recvPort(event) {
      console.log("channelByPostMessage.recvPort "+event.origin, event);
      if (event.data.indexOf(channel.protocolName) !== 0) {
        return; // not for us
      }
      window.removeEventListener('message', recvPort, false);
      if (event.ports && event.ports.length) {
        channel.port = event.ports[0];
        channel.port.onmessage = channel.recv.bind(channel);
        channel.send = function(message) { this.port.postMessage(message); };
      } else {
        // no MessageChannel support I guess.
        channel.onmessage = channel.recv.bind(channel);
        channel.source = event.source;
        channel.origin = event.origin;
        window.addEventListener('message', channel.onmessage, false);
        channel.send = function(message) {
          channel.source.postMessage(message, channel.origin);
        };
      }
      channel.features.push('channel');
    }

    function requestPort() {
      if (window.parent !== window) { // we are an iframe
        window.addEventListener('message', recvPort, false);
        window.parent.postMessage(channel.protocolName+' '+channel.version, "*"); // tell our parent we are loaded
        return true;
      } else {
        console.error("connectToBrowser must be included in an iframe");
        return false;
      }
    }

    return requestPort();
  };

  Browser.disconnect = function (channel) {
    if (channel.port) {
      channel.port.close();
    } else {
      window.removeEventListener('message', channel.onmessage, false);
    }
  };

  //---------------------------------------------------------------------------------------------
  // Implement PurplePart
  channel__.initialize = function() {
      this.protocolName ='IAmPurple';
      this.version = 1;
      console.log("Calling Browser.connect");
      Browser.connect(this);
  };

  channel__.destroy = function() {
      Browser.disconnect(this);
  };

  channel__.implementsFeature('channel');
  thePurple.registerPart(channel__);

}());
<|endoftext|>


<commit_before>var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var current_date = null;
var expanded_interviews = {};
var candidates = null;
var roundup_date = null;
var dragging_cell = null;
var placeholder_cell = null;
var start_drag_cell_y = null;
var start_drag_y = null;
var num_outstanding_requests = 0;
state_enum = {
    CANDIDATE_SELECT : 0,
    ROUNDUP_SCHEDULE : 1,
    SCHEDULING : 2,
    DONE: 3
};
var current_state = state_enum.CANDIDATE_SELECT;

window.onload = function()
{
    var date = new Date();
//    date.setDate(date.getDate() - 1);
    make_ajax_request("/api/candidate_list?date=" + Math.floor(date.getTime()/1000), update_candidate_list_ui, handle_ajax_error);
    set_date(get_roundup_date());
}

window.onmousemove = handle_drag;
window.ontouchmove = handle_drag;

function handle_drag()
{
    if (!dragging_cell)
        return;
    event.preventDefault();
    var mouse_move_delta = mouseY(event) - start_drag_y;
    var delta = start_drag_cell_y + mouse_move_delta;
    dragging_cell.style.top = delta + "px";
    var cell_to_move = null;
    if (mouse_move_delta >= dragging_cell.clientHeight && (cell_to_move = next_visible_cell(dragging_cell)))
    {
        dragging_cell.parentNode.removeChild(cell_to_move);
        dragging_cell.parentNode.insertBefore(cell_to_move, placeholder_cell);
        start_drag_cell_y += dragging_cell.clientHeight;
        start_drag_y += dragging_cell.clientHeight;
        calculate_and_refresh_roundup_times();
    }
    else if (mouse_move_delta <= -dragging_cell.clientHeight && (cell_to_move = previous_visible_cell(placeholder_cell)))
    {
        dragging_cell.parentNode.removeChild(cell_to_move);
        dragging_cell.parentNode.insertBefore(cell_to_move, dragging_cell.nextSibling);
        start_drag_cell_y -= dragging_cell.clientHeight;
        start_drag_y -= dragging_cell.clientHeight;
        calculate_and_refresh_roundup_times();
    }
}

window.onmouseup = stop_dragging;
window.ontouchend = stop_dragging;

function next_visible_cell(cell)
{
    do
    {
        cell = cell.nextSibling;
    }
    while (cell && (!has_class(cell, "tableview-cell") || has_class(cell, "collapsed")));
    return cell;
}

function previous_visible_cell(cell)
{
    do
    {
        cell = cell.previousSibling;
    }
    while (cell && (!has_class(cell, "tableview-cell") || has_class(cell, "collapsed")));
    return cell;
}

function build_content_from_template(script_id, data, target_container_id)
{
    var templateSource = document.getElementById(script_id);
    var template= Handlebars.compile(templateSource.innerHTML);
    var built_html = template(data);
    var final_html = built_html + templateSource.outerHTML;
    document.getElementById(target_container_id).innerHTML = final_html;
}

function start_dragging()
{
    if (current_state != state_enum.ROUNDUP_SCHEDULE || placeholder_cell != null)
    {
        return;
    }
    dragging_cell = get_clicked_tableviewcell(event);
    set_up_dragging_cell(dragging_cell);
    placeholder_cell = document.createElement('DIV');
    placeholder_cell.className = "tableview-cell";
    placeholder_cell.style.backgroundColor = "rgba(0, 0, 0, 0)";
    placeholder_cell.style.bottomBorder = "1px";
    placeholder_cell.id = "placeholder";
    dragging_cell.parentNode.insertBefore(placeholder_cell, dragging_cell);
    start_drag_y = mouseY(event);
}

function get_supported_property(property_array)
{
    var root = document.documentElement;
    for (var i = 0; i < property_array.length; i++)
    {
        if (property_array[i] in root.style)
        {
            return property_array[i];
        }
    }
}

function set_up_dragging_cell(cell)
{
    cell.className = cell.className.replace("transition", "");
    cell.style.position = "absolute";
    var cells = cell.parentNode.children;
    var num_visible_cells_above = 0;
    for (var indexOfCell = 0; indexOfCell < cells.length; indexOfCell++)
    {
        if (cells[indexOfCell] == cell)
            break;
        else if (!has_class(cells[indexOfCell], "collapsed"))
        {
            num_visible_cells_above++;
        }
    }
    start_drag_cell_y = num_visible_cells_above* cell.clientHeight;
    cell.style.top = (start_drag_cell_y - 1) +  "px";
    cell.style.zIndex = 1;
    var box_shadow_prop = get_supported_property(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow']);
    cell.style[box_shadow_prop] = "0 8px 6px -6px #AAAAAA";
}

function stop_dragging()
{
    if (current_state != state_enum.ROUNDUP_SCHEDULE || dragging_cell == null)
    {
        return;
    }
    tear_down_dragging_cell(dragging_cell);
    dragging_cell = null;
    start_dragging_y = null;
}

function tear_down_dragging_cell(cell)
{
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'mozTransitionEnd',
        'oTransitionEnd'
    ];
    var animation_end_callback = function()
    {
        for (var i = 0; i < events.length; i++)
        {
            cell.removeEventListener(events[i], animation_end_callback, false);
        }
        cell.className = cell.className.replace("transition", "");
        placeholder_cell.parentNode.removeChild(placeholder_cell);
        placeholder_cell = null;
        cell.style.top = "0px";
        cell.style.position = "relative";
        var box_shadow_prop = get_supported_property(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow']);
        cell.style[box_shadow_prop] = "0px";
        cell.style.zIndex = 0;
    }
    for (var i = 0; i < events.length; i++)
    {
        cell.addEventListener(events[i], animation_end_callback, false);
    }
    cell.className += " transition";
    cell.style.top = start_drag_cell_y + "px";
}

function get_clicked_tableviewcell(event)
{
    var clickedElement = event.toElement || event.target;
    var tableviewcell = clickedElement;
    while (!has_class(tableviewcell, "tableview-cell") && tableviewcell.parentNode)
    {
        tableviewcell = tableviewcell.parentNode;
    }
    return tableviewcell;
}

function toggle_checkmark()
{
    if (current_state == state_enum.CANDIDATE_SELECT)
    {
        var tableviewcell = get_clicked_tableviewcell(event);
        var checkbox = tableviewcell.getElementsByClassName("checkbox")[0];
        if (checkbox.innerHTML.length == 0)
            checkbox.innerHTML = "✓";
        else
            checkbox.innerHTML = "";
    }
}

function set_date(new_date)
{
    if (!new_date)
    {
        new_date = new Date();
        // Round to the nearest second
        new_date = new Date(Math.floor(new_date.getTime()/1000) * 1000);
    }
    document.getElementById('date').innerHTML = days[new_date.getDay()] + ", " + months[new_date.getMonth()] + " " + new_date.getDate();
}

function check_authn(data)
{
    if (data["error"] == "authn_needed")
    {
        var authn_form = document.getElementById("authn_form");
        document.getElementById('saml_response_input').value = data["authn_request"];
        document.getElementById('saml_relay_state_input').value = (window.location.hash == null || window.location.hash.length == 0)? "dashboard" : window.location.hash;
        authn_form.submit();
        return true;
    }
    return false;
}

function update_candidate_list_ui(data)
{
    if (typeof data == 'string')
    {
        data = JSON.parse(data);
    }

    candidates = data["candidates"];
    Handlebars.registerHelper('list', function(candidates, options)
    {
        var out = "";
        var candidateHTML;
        for (var i = 0, length = candidates.length; i < length; i++)
        {
            candidate_dict = candidates[i];
            candidate_dict["candidate_index"] = i;
            candidateHTML = options.fn(candidate_dict);
            out = out + candidateHTML;
        }
        return out;
    });
    build_content_from_template('candidates_handlebars', data, 'candidate_list_tableview');
}

function get_roundup_date()
{
    if (!roundup_date)
    {
        var now = new Date();
        var num_days_to_add = 1;
        if (now.getDay() >= 5)
        {
            num_days_to_add = (7 - now.getDay())%7 + 1;
        }
        roundup_date = now;
        roundup_date.setDate(now.getDate() + num_days_to_add);
    }
    roundup_date.setHours(10);
    roundup_date.setMinutes(30);
    return roundup_date;
}

function handle_major_button_clicked()
{
    if (current_state == state_enum.CANDIDATE_SELECT)
    {
        var tableviewcells = document.getElementById("candidate_list_tableview").getElementsByClassName("tableview-cell");
        var num_selected = 0;
        for (var i = 0; i < tableviewcells.length; i++)
        {
            var checkbox = tableviewcells[i].getElementsByClassName("checkbox")[0];
            checkbox.className = checkbox.className.replace("checkbox", "timebox");
            if (checkbox.innerHTML.length == 0)
            {
                tableviewcells[i].className += " collapsed";
            }
            else
            {
                num_selected++;
            }
            checkbox.innerHTML = "";
        }
        calculate_and_refresh_roundup_times();
        current_state = state_enum.ROUNDUP_SCHEDULE;
    }
    else if (current_state == state_enum.ROUNDUP_SCHEDULE)
    {

        var roundup_data = calculate_and_refresh_roundup_times();
        num_outstanding_requests = roundup_data.length;
        for (var i = 0; i < roundup_data.length; i++)
        {
            make_ajax_request("/api/schedule_roundup?candidate_name=" + encodeURIComponent(roundup_data[i].candidate_name) + "&start_date=" + roundup_data[i].start_date + "&length=" + roundup_data[i].length, handle_roundup_schedule_response, handle_ajax_error);
        }
        current_state = state_enum.SCHEDULING;
    }
    refresh_major_button();
}

function handle_roundup_schedule_response(data)
{
    if (data.status == "success")
    {
        num_outstanding_requests--;
        if (num_outstanding_requests == 0)
        {
            current_state = state_enum.DONE;
        }
    }
    else
    {
        num_outstanding_requests--;
        handle_ajax_error(JSON.stringify(data));
    }
    refresh_major_button();
}

function refresh_major_button()
{
    var button_text = "";
    if (current_state == state_enum.ROUNDUP_SCHEDULE)
    {
        button_text = "Schedule Roundups";
    }
    else if (current_state == state_enum.CANDIDATE_SELECT)
    {
        button_text = "Select Candidates";
    }
    else if (current_state == state_enum.SCHEDULING)
    {
        button_text = "Scheduling...";
    }
    else if (current_state == state_enum.DONE)
    {
        button_text = "Done";
    }
    var button_element = document.getElementsByClassName("major-button")[0];
    button_element.innerHTML = button_text;
}

function calculate_and_refresh_roundup_times()
{
    var tableviewcells = document.getElementById("candidate_list_tableview").getElementsByClassName("tableview-cell");
    var num_visible = 0;
    for (var i = 0; i < tableviewcells.length; i++)
    {
        if (!has_class(tableviewcells[i], "collapsed") && tableviewcells[i].id != "placeholder")
        {
            num_visible++;
        }
    }
    var roundup_start = get_roundup_date();
    var roundup_length = Math.min(15, 60/num_visible);
    var roundups = [];
    for (var i = 0; i < tableviewcells.length; i++)
    {
        if (!has_class(tableviewcells[i], "collapsed") && tableviewcells[i].id != "placeholder")
        {
            var timebox = tableviewcells[i].getElementsByClassName("timebox")[0];
            timebox.innerHTML = pad(roundup_start.getHours(), 2) + ":" + pad(roundup_start.getMinutes(), 2);
            roundups.push({
                'candidate_name' : candidates[tableviewcells[i].id].candidate_name,
                'start_date' : Math.floor(roundup_start.getTime()/1000),
                'length' : Math.floor(roundup_length)
            });
            roundup_start.setMinutes(roundup_start.getMinutes() + roundup_length);
        }
    }
    return roundups;
}

function handle_ajax_error(error_string)
{
    alert(error_string);
}

function has_class(element, cls)
{
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

function mouseY(e)
{
    if (e.pageY)
    {
        return e.pageY;
    }
    if (e.clientY)
    {
        return e.clientY + (document.documentElement.scrollTop ?
        document.documentElement.scrollTop :
        document.body.scrollTop);
    }
    return null;
}

function pad(num, size)
{
    var s = num+"";
    while (s.length < size) s = "0" + s;
    return s;
}
<commit_msg>Roundup scheduling should skip Tuesday<commit_after>var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var current_date = null;
var expanded_interviews = {};
var candidates = null;
var roundup_date = null;
var dragging_cell = null;
var placeholder_cell = null;
var start_drag_cell_y = null;
var start_drag_y = null;
var num_outstanding_requests = 0;
state_enum = {
    CANDIDATE_SELECT : 0,
    ROUNDUP_SCHEDULE : 1,
    SCHEDULING : 2,
    DONE: 3
};
var current_state = state_enum.CANDIDATE_SELECT;

window.onload = function()
{
    var date = new Date();
//    date.setDate(date.getDate() - 1);
    make_ajax_request("/api/candidate_list?date=" + Math.floor(date.getTime()/1000), update_candidate_list_ui, handle_ajax_error);
    set_date(get_roundup_date());
}

window.onmousemove = handle_drag;
window.ontouchmove = handle_drag;

function handle_drag()
{
    if (!dragging_cell)
        return;
    event.preventDefault();
    var mouse_move_delta = mouseY(event) - start_drag_y;
    var delta = start_drag_cell_y + mouse_move_delta;
    dragging_cell.style.top = delta + "px";
    var cell_to_move = null;
    if (mouse_move_delta >= dragging_cell.clientHeight && (cell_to_move = next_visible_cell(dragging_cell)))
    {
        dragging_cell.parentNode.removeChild(cell_to_move);
        dragging_cell.parentNode.insertBefore(cell_to_move, placeholder_cell);
        start_drag_cell_y += dragging_cell.clientHeight;
        start_drag_y += dragging_cell.clientHeight;
        calculate_and_refresh_roundup_times();
    }
    else if (mouse_move_delta <= -dragging_cell.clientHeight && (cell_to_move = previous_visible_cell(placeholder_cell)))
    {
        dragging_cell.parentNode.removeChild(cell_to_move);
        dragging_cell.parentNode.insertBefore(cell_to_move, dragging_cell.nextSibling);
        start_drag_cell_y -= dragging_cell.clientHeight;
        start_drag_y -= dragging_cell.clientHeight;
        calculate_and_refresh_roundup_times();
    }
}

window.onmouseup = stop_dragging;
window.ontouchend = stop_dragging;

function next_visible_cell(cell)
{
    do
    {
        cell = cell.nextSibling;
    }
    while (cell && (!has_class(cell, "tableview-cell") || has_class(cell, "collapsed")));
    return cell;
}

function previous_visible_cell(cell)
{
    do
    {
        cell = cell.previousSibling;
    }
    while (cell && (!has_class(cell, "tableview-cell") || has_class(cell, "collapsed")));
    return cell;
}

function build_content_from_template(script_id, data, target_container_id)
{
    var templateSource = document.getElementById(script_id);
    var template= Handlebars.compile(templateSource.innerHTML);
    var built_html = template(data);
    var final_html = built_html + templateSource.outerHTML;
    document.getElementById(target_container_id).innerHTML = final_html;
}

function start_dragging()
{
    if (current_state != state_enum.ROUNDUP_SCHEDULE || placeholder_cell != null)
    {
        return;
    }
    dragging_cell = get_clicked_tableviewcell(event);
    set_up_dragging_cell(dragging_cell);
    placeholder_cell = document.createElement('DIV');
    placeholder_cell.className = "tableview-cell";
    placeholder_cell.style.backgroundColor = "rgba(0, 0, 0, 0)";
    placeholder_cell.style.bottomBorder = "1px";
    placeholder_cell.id = "placeholder";
    dragging_cell.parentNode.insertBefore(placeholder_cell, dragging_cell);
    start_drag_y = mouseY(event);
}

function get_supported_property(property_array)
{
    var root = document.documentElement;
    for (var i = 0; i < property_array.length; i++)
    {
        if (property_array[i] in root.style)
        {
            return property_array[i];
        }
    }
}

function set_up_dragging_cell(cell)
{
    cell.className = cell.className.replace("transition", "");
    cell.style.position = "absolute";
    var cells = cell.parentNode.children;
    var num_visible_cells_above = 0;
    for (var indexOfCell = 0; indexOfCell < cells.length; indexOfCell++)
    {
        if (cells[indexOfCell] == cell)
            break;
        else if (!has_class(cells[indexOfCell], "collapsed"))
        {
            num_visible_cells_above++;
        }
    }
    start_drag_cell_y = num_visible_cells_above* cell.clientHeight;
    cell.style.top = (start_drag_cell_y - 1) +  "px";
    cell.style.zIndex = 1;
    var box_shadow_prop = get_supported_property(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow']);
    cell.style[box_shadow_prop] = "0 8px 6px -6px #AAAAAA";
}

function stop_dragging()
{
    if (current_state != state_enum.ROUNDUP_SCHEDULE || dragging_cell == null)
    {
        return;
    }
    tear_down_dragging_cell(dragging_cell);
    dragging_cell = null;
    start_dragging_y = null;
}

function tear_down_dragging_cell(cell)
{
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'mozTransitionEnd',
        'oTransitionEnd'
    ];
    var animation_end_callback = function()
    {
        for (var i = 0; i < events.length; i++)
        {
            cell.removeEventListener(events[i], animation_end_callback, false);
        }
        cell.className = cell.className.replace("transition", "");
        placeholder_cell.parentNode.removeChild(placeholder_cell);
        placeholder_cell = null;
        cell.style.top = "0px";
        cell.style.position = "relative";
        var box_shadow_prop = get_supported_property(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow']);
        cell.style[box_shadow_prop] = "0px";
        cell.style.zIndex = 0;
    }
    for (var i = 0; i < events.length; i++)
    {
        cell.addEventListener(events[i], animation_end_callback, false);
    }
    cell.className += " transition";
    cell.style.top = start_drag_cell_y + "px";
}

function get_clicked_tableviewcell(event)
{
    var clickedElement = event.toElement || event.target;
    var tableviewcell = clickedElement;
    while (!has_class(tableviewcell, "tableview-cell") && tableviewcell.parentNode)
    {
        tableviewcell = tableviewcell.parentNode;
    }
    return tableviewcell;
}

function toggle_checkmark()
{
    if (current_state == state_enum.CANDIDATE_SELECT)
    {
        var tableviewcell = get_clicked_tableviewcell(event);
        var checkbox = tableviewcell.getElementsByClassName("checkbox")[0];
        if (checkbox.innerHTML.length == 0)
            checkbox.innerHTML = "✓";
        else
            checkbox.innerHTML = "";
    }
}

function set_date(new_date)
{
    if (!new_date)
    {
        new_date = new Date();
        // Round to the nearest second
        new_date = new Date(Math.floor(new_date.getTime()/1000) * 1000);
    }
    document.getElementById('date').innerHTML = days[new_date.getDay()] + ", " + months[new_date.getMonth()] + " " + new_date.getDate();
}

function check_authn(data)
{
    if (data["error"] == "authn_needed")
    {
        var authn_form = document.getElementById("authn_form");
        document.getElementById('saml_response_input').value = data["authn_request"];
        document.getElementById('saml_relay_state_input').value = (window.location.hash == null || window.location.hash.length == 0)? "dashboard" : window.location.hash;
        authn_form.submit();
        return true;
    }
    return false;
}

function update_candidate_list_ui(data)
{
    if (typeof data == 'string')
    {
        data = JSON.parse(data);
    }

    candidates = data["candidates"];
    Handlebars.registerHelper('list', function(candidates, options)
    {
        var out = "";
        var candidateHTML;
        for (var i = 0, length = candidates.length; i < length; i++)
        {
            candidate_dict = candidates[i];
            candidate_dict["candidate_index"] = i;
            candidateHTML = options.fn(candidate_dict);
            out = out + candidateHTML;
        }
        return out;
    });
    build_content_from_template('candidates_handlebars', data, 'candidate_list_tableview');
}

function get_roundup_date()
{
    if (!roundup_date)
    {
        var now = new Date();
        var num_days_to_add = 1;
        switch (now.getDay()) {
            case 5: // Friday - shoot for Monday
                num_days_to_add = 3;
                break;
            case 6: // Saturday - shoot for Monday
            case 1: // Monday - shoot for Wednesday
                num_days_to_add = 2;
                break;
        }
        roundup_date = now;
        roundup_date.setDate(now.getDate() + num_days_to_add);
    }
    roundup_date.setHours(10);
    roundup_date.setMinutes(30);
    return roundup_date;
}

function handle_major_button_clicked()
{
    if (current_state == state_enum.CANDIDATE_SELECT)
    {
        var tableviewcells = document.getElementById("candidate_list_tableview").getElementsByClassName("tableview-cell");
        var num_selected = 0;
        for (var i = 0; i < tableviewcells.length; i++)
        {
            var checkbox = tableviewcells[i].getElementsByClassName("checkbox")[0];
            checkbox.className = checkbox.className.replace("checkbox", "timebox");
            if (checkbox.innerHTML.length == 0)
            {
                tableviewcells[i].className += " collapsed";
            }
            else
            {
                num_selected++;
            }
            checkbox.innerHTML = "";
        }
        calculate_and_refresh_roundup_times();
        current_state = state_enum.ROUNDUP_SCHEDULE;
    }
    else if (current_state == state_enum.ROUNDUP_SCHEDULE)
    {

        var roundup_data = calculate_and_refresh_roundup_times();
        num_outstanding_requests = roundup_data.length;
        for (var i = 0; i < roundup_data.length; i++)
        {
            make_ajax_request("/api/schedule_roundup?candidate_name=" + encodeURIComponent(roundup_data[i].candidate_name) + "&start_date=" + roundup_data[i].start_date + "&length=" + roundup_data[i].length, handle_roundup_schedule_response, handle_ajax_error);
        }
        current_state = state_enum.SCHEDULING;
    }
    refresh_major_button();
}

function handle_roundup_schedule_response(data)
{
    if (data.status == "success")
    {
        num_outstanding_requests--;
        if (num_outstanding_requests == 0)
        {
            current_state = state_enum.DONE;
        }
    }
    else
    {
        num_outstanding_requests--;
        handle_ajax_error(JSON.stringify(data));
    }
    refresh_major_button();
}

function refresh_major_button()
{
    var button_text = "";
    if (current_state == state_enum.ROUNDUP_SCHEDULE)
    {
        button_text = "Schedule Roundups";
    }
    else if (current_state == state_enum.CANDIDATE_SELECT)
    {
        button_text = "Select Candidates";
    }
    else if (current_state == state_enum.SCHEDULING)
    {
        button_text = "Scheduling...";
    }
    else if (current_state == state_enum.DONE)
    {
        button_text = "Done";
    }
    var button_element = document.getElementsByClassName("major-button")[0];
    button_element.innerHTML = button_text;
}

function calculate_and_refresh_roundup_times()
{
    var tableviewcells = document.getElementById("candidate_list_tableview").getElementsByClassName("tableview-cell");
    var num_visible = 0;
    for (var i = 0; i < tableviewcells.length; i++)
    {
        if (!has_class(tableviewcells[i], "collapsed") && tableviewcells[i].id != "placeholder")
        {
            num_visible++;
        }
    }
    var roundup_start = get_roundup_date();
    var roundup_length = Math.min(15, 60/num_visible);
    var roundups = [];
    for (var i = 0; i < tableviewcells.length; i++)
    {
        if (!has_class(tableviewcells[i], "collapsed") && tableviewcells[i].id != "placeholder")
        {
            var timebox = tableviewcells[i].getElementsByClassName("timebox")[0];
            timebox.innerHTML = pad(roundup_start.getHours(), 2) + ":" + pad(roundup_start.getMinutes(), 2);
            roundups.push({
                'candidate_name' : candidates[tableviewcells[i].id].candidate_name,
                'start_date' : Math.floor(roundup_start.getTime()/1000),
                'length' : Math.floor(roundup_length)
            });
            roundup_start.setMinutes(roundup_start.getMinutes() + roundup_length);
        }
    }
    return roundups;
}

function handle_ajax_error(error_string)
{
    alert(error_string);
}

function has_class(element, cls)
{
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

function mouseY(e)
{
    if (e.pageY)
    {
        return e.pageY;
    }
    if (e.clientY)
    {
        return e.clientY + (document.documentElement.scrollTop ?
        document.documentElement.scrollTop :
        document.body.scrollTop);
    }
    return null;
}

function pad(num, size)
{
    var s = num+"";
    while (s.length < size) s = "0" + s;
    return s;
}
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var mongoose = require('mongoose')
  , Citizen = mongoose.model('Citizen')
  , log = require('debug')('democracyos:db-api:citizen');

/**
 * Get all citizens
 *
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list items found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.all = function all(fn) {
  log('Looking for all citizens.');

  Citizen
  .find()
  .sort('-createdAt')
  .exec(function (err, citizens) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering all citizens %j', pluck(citizens, 'id'));
    fn(null, citizens);
  });
  return this;
}

/**
 * Get Citizen for `id` string or `ObjectId`
 *
 * @param {String|ObjectId} id Citizen's `id`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizen' single object created or `undefined`
 * @api public
 */

exports.get = function get(id, fn) {
  log('Looking for Citizen %s', id);

  Citizen
  .findById(id)
  .exec(function (err, citizen) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering Citizen %j', citizen);
    fn(null, citizen);
  });
  return this;
};

/**
 * Search `Citizen` objects from query
 *
 * @param {String} query string to search by `hash`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list of `Citizen` objects found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.search = function search(query, fn) {
  var hashQuery = new RegExp('.*' + query + '.*','i');

  log('Searching for Citizens matching %s', hashQuery);

  Citizen.find()
  .or([{firstName: hashQuery}, {lastName: hashQuery}])
  .select('firstName lastName fullName avatar')
  .exec(function(err, citizens) {
    if (err) {
      log('Found error: %j', err);
      return fn(err);
    }

    log('Found Citizens %j for hash %s', citizens, hashQuery)
    fn(null, citizens);
  });

  return this;
};

/**
 * Lookup `Citizen`s objects by ids
 *
 * @param {Array} ids array to search by
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list of `Citizen` objects found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.lookup = function search(ids, fn) {
  log('Searching for Citizens by ids %s', ids);

  Citizen.find({ _id: { $in: ids }})
  .select('firstName lastName fullName avatar')
  .exec(function(err, citizens) {
    if (err) return log('Found error: %j', err), fn(err);

    log('Found Citizens %j for hash %s', citizens, hashQuery);
    fn(null, citizens);
  });

  return this;
};

/**
 * Map array of objects by `property`
 *
 * @param {Array} source array of objects to map
 * @param {String} property to map from objects
 * @return {Array} array of listed properties
 * @api private
 */

function pluck (source, property) {
  return source.map(function (item) { return item[property]; });
}<commit_msg>[db-api:citizen] - Fix log error<commit_after>/**
 * Module dependencies.
 */

var mongoose = require('mongoose')
  , Citizen = mongoose.model('Citizen')
  , log = require('debug')('democracyos:db-api:citizen');

/**
 * Get all citizens
 *
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list items found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.all = function all(fn) {
  log('Looking for all citizens.');

  Citizen
  .find()
  .sort('-createdAt')
  .exec(function (err, citizens) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering all citizens %j', pluck(citizens, 'id'));
    fn(null, citizens);
  });
  return this;
}

/**
 * Get Citizen for `id` string or `ObjectId`
 *
 * @param {String|ObjectId} id Citizen's `id`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizen' single object created or `undefined`
 * @api public
 */

exports.get = function get(id, fn) {
  log('Looking for Citizen %s', id);

  Citizen
  .findById(id)
  .exec(function (err, citizen) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering Citizen %j', citizen);
    fn(null, citizen);
  });
  return this;
};

/**
 * Search `Citizen` objects from query
 *
 * @param {String} query string to search by `hash`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list of `Citizen` objects found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.search = function search(query, fn) {
  var hashQuery = new RegExp('.*' + query + '.*','i');

  log('Searching for Citizens matching %s', hashQuery);

  Citizen.find()
  .or([{firstName: hashQuery}, {lastName: hashQuery}])
  .select('firstName lastName fullName avatar')
  .exec(function(err, citizens) {
    if (err) {
      log('Found error: %j', err);
      return fn(err);
    }

    log('Found Citizens %j for hash %s', citizens, hashQuery)
    fn(null, citizens);
  });

  return this;
};

/**
 * Lookup `Citizen`s objects by ids
 *
 * @param {Array} ids array to search by
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'citizens' list of `Citizen` objects found or `undefined`
 * @return {Module} `citizen` module
 * @api public
 */

exports.lookup = function search(ids, fn) {
  log('Searching for Citizens by ids %s', ids);

  Citizen.find({ _id: { $in: ids }})
  .select('firstName lastName fullName avatar')
  .exec(function(err, citizens) {
    if (err) return log('Found error: %j', err), fn(err);

    log('Found Citizens %j', citizens);
    fn(null, citizens);
  });

  return this;
};

/**
 * Map array of objects by `property`
 *
 * @param {Array} source array of objects to map
 * @param {String} property to map from objects
 * @return {Array} array of listed properties
 * @api private
 */

function pluck (source, property) {
  return source.map(function (item) { return item[property]; });
}<|endoftext|>


<commit_before>module.exports = {
  autoAssign: true,
  keyword: '@todo',
  blobLines: 5,
  caseSensitive: false,
  label: true
}
<commit_msg>Add default config<commit_after>module.exports = {
  autoAssign: true,
  keyword: '@todo',
  blobLines: 5,
  caseSensitive: false,
  label: true,
  reopenClosed: true
}
<|endoftext|>


<commit_before>"use strict"

var port = browser.runtime.connect({name: "connection-to-legacy"});

//
// Handle addon settings
//
var defaultSettings = {
    right: false,
    hideInFullscreen: true,
    compact: false,
    theme: "dark",
    tabtoolbarPosition: "top",
    toggleDisplayHotkey: "control-alt-v",
    width: 250,
    debug: false
}

function restore_default_settings()
{
    Object.keys(defaultSettings).forEach(function(k)
    {
        save_setting(k, defaultSettings[k]);
        sdk_send_changed_setting(k);
    });
}

function save_setting(name, value)
{
    let settingsObject = {};
    settingsObject[name] = value;

    browser.storage.local.set(settingsObject).then(error =>
    {
        if(error)
        {
            return false;
        }

        return true;
    });
}

function get_setting(name)
{
    return new Promise(function (fulfill, reject)
    {
        browser.storage.local.get(name).then(results =>
        {
            if (!results.hasOwnProperty(name))
            {
                debug_log("VTR WebExt setting '"+ name +"': not saved use default value.");
                if(defaultSettings.hasOwnProperty(name))
                {
                    results[name] = defaultSettings[name];
                }
                else
                {
                    debug_log("VTR WebExt setting '"+ name +"': no default value found.");
                }
            }

            fulfill(results[name]);
        }).catch(
            function(reason) {
                debug_log(reason);
            }
        );
    });
}

//
// CSS Mangament
//

function css_load_file(filename)
{
    return new Promise(function (fulfill, reject)
    {
        var read = new XMLHttpRequest();
        debug_log(browser.runtime.getURL("data/"+filename));
        read.open("GET", browser.runtime.getURL("data/"+filename), false);
        read.onreadystatechange = function()
        {
            //console.log(read.responseText);
            fulfill(read.responseText);
        }
        read.send();
    });
}

//
// Communication with the legacy part + content script
//

function sdk_send_all_settings()
{
    browser.storage.local.get().then(value => {
        value["dataPath"] = browser.runtime.getURL("data/");
        sdk_sendMsg({
            type: "settings.post-all",
            value: value
        });
    });
}

sdk_send_all_settings();

// Changed addon preferences, send to SDK
function sdk_send_changed_setting(settingName)
{
    sdk_send_all_settings();

    if(settingName == "toggleDisplayHotkey")
    {
        sdk_sendMsg({type: "settings.toggleDisplayHotkey"});
    }

    get_setting(settingName).then(value => {
        sdk_sendMsg({
            type: "settings.post",
            name: settingName,
            value: value
        });
    });
}

function sdk_replyHandler(message)
{
    if(message.type == "settings.post")
    {
        // the legacy part sent settings, save them
        save_setting(message.name, message.value);
    }

    if(message.type == "settings.post-to-sdk")
    {
        // the very-very-legacy part of the add-on wants to save settings
        save_setting(message.name, message.value);
        message.type = "settings.post";
        sdk_sendMsg(message);
    }

    if(message.type == "settings.reset")
    {
        restore_default_settings();
    }

    /*if(message.type == "css.get")
    {
        if(message.file == "none")
        {
            // Reset some saved CSS values
            sdk_sendMsg({type: "css.post", name: message.name, value: ""});
        }
        else
        {
            css_load_file(message.file).then(css =>
            {
                sdk_sendMsg({type: "css.post", name: message.name, value: css});
            });
        }
    }*/

    if(message.type == "debug.log")
    {
        debug_log(message.value);
    }
}

port.onMessage.addListener(sdk_replyHandler); // legacy listener
browser.runtime.onMessage.addListener(sdk_replyHandler); // content script listener

function sdk_sendMsg(message)
{
    browser.runtime.sendMessage(message).then(reply =>
    {
        if (reply) {
            sdk_replyHandler(reply);
        }
    });
}

// Get all settings from the legacy part
setTimeout(function(){
    sdk_sendMsg({type: "settings.get", name: "right"});
    sdk_sendMsg({type: "settings.get", name: "hideInFullscreen"});
    sdk_sendMsg({type: "settings.get", name: "theme"});
    sdk_sendMsg({type: "settings.get", name: "tabtoolbarPosition"});
    sdk_sendMsg({type: "settings.get", name: "toggleDisplayHotkey"});
    sdk_sendMsg({type: "settings.get", name: "width"});
    sdk_sendMsg({type: "settings.get", name: "debug"});

    browser.storage.onChanged.addListener(sdk_send_all_settings);
}, 100);

// Utils
function debug_log(output)
{
	get_setting("debug").then(value => {
        if(value == true)
        {
            console.log(output);
        }
	});
}
<commit_msg>Reset setting showHiddenSettings as well on user triggered reset<commit_after>"use strict"

var port = browser.runtime.connect({name: "connection-to-legacy"});

//
// Handle addon settings
//
var defaultSettings = {
    right: false,
    hideInFullscreen: true,
    compact: false,
    theme: "dark",
    tabtoolbarPosition: "top",
    toggleDisplayHotkey: "control-alt-v",
    width: 250,
    debug: false,
    showHiddenSettings: false
}

function restore_default_settings()
{
    Object.keys(defaultSettings).forEach(function(k)
    {
        save_setting(k, defaultSettings[k]);
        sdk_send_changed_setting(k);
    });
}

function save_setting(name, value)
{
    let settingsObject = {};
    settingsObject[name] = value;

    browser.storage.local.set(settingsObject).then(error =>
    {
        if(error)
        {
            return false;
        }

        return true;
    });
}

function get_setting(name)
{
    return new Promise(function (fulfill, reject)
    {
        browser.storage.local.get(name).then(results =>
        {
            if (!results.hasOwnProperty(name))
            {
                debug_log("VTR WebExt setting '"+ name +"': not saved use default value.");
                if(defaultSettings.hasOwnProperty(name))
                {
                    results[name] = defaultSettings[name];
                }
                else
                {
                    debug_log("VTR WebExt setting '"+ name +"': no default value found.");
                }
            }

            fulfill(results[name]);
        }).catch(
            function(reason) {
                debug_log(reason);
            }
        );
    });
}

//
// CSS Mangament
//

function css_load_file(filename)
{
    return new Promise(function (fulfill, reject)
    {
        var read = new XMLHttpRequest();
        debug_log(browser.runtime.getURL("data/"+filename));
        read.open("GET", browser.runtime.getURL("data/"+filename), false);
        read.onreadystatechange = function()
        {
            //console.log(read.responseText);
            fulfill(read.responseText);
        }
        read.send();
    });
}

//
// Communication with the legacy part + content script
//

function sdk_send_all_settings()
{
    browser.storage.local.get().then(value => {
        value["dataPath"] = browser.runtime.getURL("data/");
        sdk_sendMsg({
            type: "settings.post-all",
            value: value
        });
    });
}

sdk_send_all_settings();

// Changed addon preferences, send to SDK
function sdk_send_changed_setting(settingName)
{
    sdk_send_all_settings();

    if(settingName == "toggleDisplayHotkey")
    {
        sdk_sendMsg({type: "settings.toggleDisplayHotkey"});
    }

    get_setting(settingName).then(value => {
        sdk_sendMsg({
            type: "settings.post",
            name: settingName,
            value: value
        });
    });
}

function sdk_replyHandler(message)
{
    if(message.type == "settings.post")
    {
        // the legacy part sent settings, save them
        save_setting(message.name, message.value);
    }

    if(message.type == "settings.post-to-sdk")
    {
        // the very-very-legacy part of the add-on wants to save settings
        save_setting(message.name, message.value);
        message.type = "settings.post";
        sdk_sendMsg(message);
    }

    if(message.type == "settings.reset")
    {
        restore_default_settings();
    }

    /*if(message.type == "css.get")
    {
        if(message.file == "none")
        {
            // Reset some saved CSS values
            sdk_sendMsg({type: "css.post", name: message.name, value: ""});
        }
        else
        {
            css_load_file(message.file).then(css =>
            {
                sdk_sendMsg({type: "css.post", name: message.name, value: css});
            });
        }
    }*/

    if(message.type == "debug.log")
    {
        debug_log(message.value);
    }
}

port.onMessage.addListener(sdk_replyHandler); // legacy listener
browser.runtime.onMessage.addListener(sdk_replyHandler); // content script listener

function sdk_sendMsg(message)
{
    browser.runtime.sendMessage(message).then(reply =>
    {
        if (reply) {
            sdk_replyHandler(reply);
        }
    });
}

// Get all settings from the legacy part
setTimeout(function(){
    sdk_sendMsg({type: "settings.get", name: "right"});
    sdk_sendMsg({type: "settings.get", name: "hideInFullscreen"});
    sdk_sendMsg({type: "settings.get", name: "theme"});
    sdk_sendMsg({type: "settings.get", name: "tabtoolbarPosition"});
    sdk_sendMsg({type: "settings.get", name: "toggleDisplayHotkey"});
    sdk_sendMsg({type: "settings.get", name: "width"});
    sdk_sendMsg({type: "settings.get", name: "debug"});

    browser.storage.onChanged.addListener(sdk_send_all_settings);
}, 100);

// Utils
function debug_log(output)
{
	get_setting("debug").then(value => {
        if(value == true)
        {
            console.log(output);
        }
	});
}
<|endoftext|>


<commit_before>const path = require('path')
const fs = require('fs')

const { readFile, fileExist, mkdirp, symlink } = require('./fs.utils')
const { log } = require('./log.utils')

module.exports = exports = configFilename => {
  return (modules, options) => {
    if (!fileExist(configFilename)) {
      log({ type: 'error', message: 'No configuration file. You need to run the init command before.' })
      return
    }

    readFile(configFilename)
      .then(data => JSON.parse(data))
      .then(data => {
        data.files = processModuleData(modules, data.folder_path)

        return data
      })
      .then(data => createDirs(data.files).then(() => data))
      .then(data => createLinks(data.files).then(() => data))
      .then(data => {

        return data
      })
      .then(data => console.log(JSON.stringify(data, null, 2)))
      .catch(error => {
        if (error.code === 'EEXIST') {
          throw new Error('symlink_already_exist')
        }

        throw error
      })
      .catch(error => {
        switch (error.message) {
          case 'symlink_already_exist':
            log({ type: 'warn', message: 'Unable to link some files. This files already exist.' })
            break
          default:
            log({ type: 'error', message: 'An error occured.', prefix: ' Fail ' })
            console.error(error)
        }
      })
  }
}

function createDirs(files) {
  const mkdirPromises = files
    .map(file => path.dirname(file.to))
    .filter(dir => !fileExist(dir))
    .map(dir => mkdirp(dir))

  return Promise.all(mkdirPromises).then(() => files)
}

function createLinks(files) {
  const linkPromises = files
    .map(file => symlink(file.from, file.to))

  return Promise.all(linkPromises).then(() => files)
}

function processModuleData(moduleNames, folderPath) {
  return moduleNames
    .map(name => {
      const addr = path.join(folderPath, 'files', name)

      let settings = []
      try {
        const file = fs.readFileSync(path.join(addr, 'settings.json'))
        settings = JSON.parse(file)
      } catch(e) {
        log({ type: 'warn', message: `Not able to load settings file for "${name}" module.` })
      }

      return { name, folder: addr, settings }
    })
    .filter(moduleConf => moduleConf.settings.length > 0)
    .map(moduleConf => {
      return moduleConf.settings
        .filter(file => file.global)
        .map(file => ({
          from: path.resolve(moduleConf.folder, file.filename),
          to: path.resolve(file['target-path'].replace('~', process.env.HOME))
        }))
    })
    .reduce((files, modules) => {
      for (const file of modules) {
        files.push(file)
      }

      return files
    }, [])
}
<commit_msg>Refactor deploy.commande.js<commit_after>const path = require('path')
const fs = require('fs')

const { readFile, fileExist, mkdirp, symlink } = require('./fs.utils')
const { log } = require('./log.utils')

module.exports = exports = configFilename => {
  return (modules, options) => {
    if (!fileExist(configFilename)) {
      log({ type: 'error', message: 'No configuration file. You need to run the init command before.' })
      return
    }

    readFile(configFilename)
      .then(data => JSON.parse(data))
      .then(data => {
        data.files = processModuleData(modules, data.folder_path)

        return data
      })
      .then(data => createDirs(data.files).then(() => data))
      .then(data => createLinks(data.files)
        .then(createdLinks => {
          if (createdLinks.length < data.files.length) {
            throw new Error('symlink_already_exist')
          }
        })
        .then(() => data)
      )
      .then(data => {

        return data
      })
      .then(data => console.log(JSON.stringify(data, null, 2)))
      .catch(error => {
        switch (error.message) {
          case 'symlink_already_exist':
            log({ type: 'warn', message: 'Unable to link some files. This files already exist.' })
            break
          default:
            log({ type: 'error', message: 'An error occured.', prefix: ' Fail ' })
            console.error(error)
        }
      })
  }
}

function createDirs(files) {
  const mkdirPromises = files
    .map(file => path.dirname(file.to))
    .filter(dir => !fileExist(dir))
    .map(dir => mkdirp(dir))

  return Promise.all(mkdirPromises).then(() => files)
}

function createLinks(files) {
  const successFulLinks = []
  const linkPromises = files
    .map(file => symlink(file.from, file.to)
      .then(
        () => successFulLink.push(file.to),
        error => {
          if (error.code !== 'EEXIST') {
            throw error
          }
        }
      )
    )
  return Promise.all(linkPromises).then(() => successFulLinks)
}

function processModuleData(moduleNames, folderPath) {
  return moduleNames
    .map(name => {
      const addr = path.join(folderPath, 'files', name)

      let settings = []
      try {
        const file = fs.readFileSync(path.join(addr, 'settings.json'))
        settings = JSON.parse(file)
      } catch(e) {
        log({ type: 'warn', message: `Not able to load settings file for "${name}" module.` })
      }

      return { name, folder: addr, settings }
    })
    .filter(moduleConf => moduleConf.settings.length > 0)
    .map(moduleConf => {
      return moduleConf.settings
        .filter(file => file.global)
        .map(file => ({
          from: path.resolve(moduleConf.folder, file.filename),
          to: path.resolve(file['target-path'].replace('~', process.env.HOME))
        }))
    })
    .reduce((files, modules) => {
      for (const file of modules) {
        files.push(file)
      }

      return files
    }, [])
}
<|endoftext|>


<commit_before>module.exports = function(context) {
  var Q    = context.requireCordovaModule('q');
  var exec = require('child_process').exec;
  var dfd  = new Q.defer();

  exec('gradle getDeps', {
    cwd: context.opts.plugin.dir
  }, function() {
    dfd.resolve();
    console.log('cordova-safe - Gradle dependencies installed');
  });

  return dfd.promise;
};
<commit_msg>Use cordova logging scheme<commit_after>module.exports = function(context) {
  var Q    = context.requireCordovaModule('q');
  var exec = require('child_process').exec;
  var dfd  = new Q.defer();

  console.log('Installing "com.bridge.safe" dependencies ');
  exec('gradle getDeps', {
    cwd: context.opts.plugin.dir
  }, function() {
    dfd.resolve();
  });

  return dfd.promise;
};
<|endoftext|>


<commit_before>/*
Problems: Text always starts with first headline not with any Text.
*/
var stdin  = require('get-stdin'),
	pandoc = require('pandoc-filter'),
	child_process = require('child_process'),
	getSplitpoints, //function
	splitPandocJSONFull, //function
	findLinks,
	findTargetIndex,
	createDocumentFilename,
	callWalker,
	titleSeperator = " – "; //seperates generalTitle from part Title

stdin().then(function(stringJSON){
	console.log("gotstdin");
	var pandocJSONFull =  JSON.parse(stringJSON);

	var splits = getSplitpoints(pandocJSONFull); //helper to generate markers of where to split the document

	var documentsArray = splitPandocJSONFull(pandocJSONFull,splits); //Splits input document along splits in an array of Pandoc-JSONs.

	var newDocs = findLinks(documentsArray); //returns array of Pandoc-JSONs with rewritten links and a string for filename.

	//console.log(JSON.stringify(newDocs[1]));
	/*
	try 1doc, 2doc as input for pandoc with
	pandoc -f json 1doc.json 1doc.html

	*/

	//new docs: array[n].doc array[n].doc array[n]filename
	newDocs.forEach(function(element, index, array){
		var process = "pandoc";
		var format = "html";
		var filename = element.filename;
		if (filename.length === 0){
			filename = "filename"+index;
		}
		var pandocArguments = ["--from json",("-o "+filename+".html")];
		var pandocify = JSON.stringify(element.doc);
		var whathappend = child_process.execSync('pandoc'+' '+pandocArguments.join(" "),{input:pandocify});
		console.log(whathappend);
	});

}).catch(function(reason){
	console.error(reason);
});

getSplitpoints = function(pandocJSONFull){
	//DOES: Finds chapter headlines and their indicies
	//GETS: pandoc JSON
	//RETURNS: an array of objects:
	// [
	// {mainindex ← the index of the headline in the pandoc JSON BLOCK array
	//  title ← the headline, stripped of non-word characters},
	//…]

	var splitPoints = [];
//array with objects {start:#, end#} for saving the node with the headline in the first, the node before the next headline in the second.
	pandocJSONFull.blocks.forEach(function(element, index, array){
		if (element.t === "Header" && element.c[0] == 1){//headline first order aka chapter
			splitPoints.push({
				"mainindex":index,
				"title":pandoc. //NOTE: Do I ever need th title? For the filenames and links, the title/filename is generated in the "findLinks" function
					stringify(element.c). //stringify makes a part of the tree to a simple string with no formatting
					replace(/\W/g, '') 	//Strips all non-word characters
								//TODO: what about öä etc.? "ae äé".replace(/\W/,"") strips "ä" but not "é"
			});
		}
	});

	if(splitPoints[0].mainindex>0){ //text starts not with a headline. Add fake splitpoint, so that begin will be included.
		splitPoints.unshift({mainindex:0,title:""});
	}
	return splitPoints;
};

splitPandocJSONFull = function(pandocJSONFull, splitPoints){
	//DOES: Splits the full PandocJSON in an array of chapter length PandocJSON Objects
	//GETS:
	//  pandocJSONFull: a PandocJSON of the full document
	//  splitPoints: an array  ob ojjects, each like
	// {mainindex ← the index of the headline in the pandoc JSON BLOCK array
	//  title ← the headline of the chapter, stripped of non-word characters}
	//
	//RETURNS: Array with Pandoc-JSONs, each a chapter of the original document
	var chapterArray = [];

	splitPoints.forEach(function(element, index, array){
		var startPoint=null,
			endPoint=null,
			chapter ={},
			chapterBlocks =[];

		startPoint = element.mainindex;

		if(index === array.length-1){ //last iteration
			endPoint = pandocJSONFull.blocks.length;//end with the last main Document element. NOT length-1 since the last node should be included in contrast to the next headline!
		} else{//all other iterations
			endPoint = array[index+1].mainindex;//end before next headline
		}

		//get the blocks of a chapter from the pandocJSON
		//NOTE: Array.slice does copy contained objects by reference. This is o.k. since we don’t want to have the same content twice in different documents.
		//REMEMBER: Array.slice copies up to, but not including, endPoint!
		chapterBlocks = pandocJSONFull.blocks.slice(startPoint, endPoint);

		//create a synthetic pandoc JSON object from the
		chapter={
			"meta": JSON.parse(JSON.stringify(pandocJSONFull.meta)), //sorta dirty trick to deep copy function-less objects: http://stackoverflow.com/a/122704/263398
			"blocks": chapterBlocks,
			"pandoc-api-version":JSON.parse(JSON.stringify(pandocJSONFull["pandoc-api-version"]))
		};

		chapterArray.push(chapter); //TODO
	});

	return chapterArray;
};

findLinks = function (documentsArray){ //finds internal links
	//DOES: rewrites all links in a pandocJSON which has internal links to external links if they link to another chapter.
	//GETS: array with pandocJSON documents.
	//RETURNS: array with pandocJSON documents with rewritten links.

	var rewrittenLinksArray = [];

	documentsArray.forEach(function(element, index, array){
		rewrittenLinksArray[index]={};
		rewrittenLinksArray[index].filename = createDocumentFilename(documentsArray[index]);
		console.log("ELEMENT:\n \n ",element,"|", index);
		rewrittenLinksArray[index].doc = pandoc.walk(
				element,
				function(type,value,format,meta){
					if (type === "Link" && value[2][0].indexOf("#") === 0){// === sourceLinkId.slice(1)){
						console.log("in")
						var targetIndex = findTargetIndex(documentsArray,value[1][0]);

						if(typeof targetIndex !== "number"){
								return undefined; //no target found
						} else if (targetIndex === index) {
							return undefined;//internal link can stay. Target is in the same document
						} else {
							var filename = createDocumentFilename(documentsArray[targetIndex]);
							var newValue = value;
							//console.log("[",value[0],",",value[1],"]");

							//return pandoc.Link(value[0],value[1]);

							newValue[2][0] = filename+"."+format+value[2][0];//creates link to  OTHER document);
							console.log(newValue);
							return {t:'Link',c:newValue};
						}
					};//endif
				},"html",element.meta);//find links
	});//end foreach
	return rewrittenLinksArray;
};//endfunction

createDocumentFilename = function(singleDocumentArray){
	//GETS: a pandocJSON
	//RETURNS: a filename for the document made of the Pandoc-JSON.
	var namestring;
	if(singleDocumentArray.blocks[0].t === "Header"){
		namestring = pandoc.stringify(singleDocumentArray.blocks[0].c).replace(/\W/g, '');//http://stackoverflow.com/questions/9364400/remove-not-alphanumeric-characters-from-string-having-trouble-with-the-char
	}else{
		namestring = pandoc.stringify(singleDocumentArray).slice(0,10).replace(/\W/g, ''); //this is rather inefficient to walk all the subtree (pandoc.stringify) to create a filename
	}

	return namestring;
};

findTargetIndex = function(documentsArray,sourceLinkId){ //
	// gets documents array and sourceLinkId,
	// returns the index of the document with the link target
	var targetDocumentIndex = null;

	documentsArray.forEach(function(element, index, array){
		pandoc.walk(
			element,
			function(type,value,format,meta){
				if (type === "Header" &&  value[1][0] === sourceLinkId.slice(1)){
					targetDocumentIndex = index;
					}//endif
					return undefined;
			},"html", element.meta);//end walk find targets
	});
	return 	targetDocumentIndex;
};
<commit_msg>working version, but same headline texts causes same file names<commit_after>/*
Problems: Text always starts with first headline not with any Text.
*/
var stdin  = require('get-stdin'),
	pandoc = require('pandoc-filter'),
	child_process = require('child_process'),
	getSplitpoints, //function
	splitPandocJSONFull, //function
	findLinks,
	findTargetIndex,
	createDocumentFilename,
	callWalker,
	titleSeperator = " – "; //seperates generalTitle from part Title

stdin().then(function(stringJSON){
	console.log("gotstdin");
	var pandocJSONFull =  JSON.parse(stringJSON);

	var splits = getSplitpoints(pandocJSONFull); //helper to generate markers of where to split the document

	var documentsArray = splitPandocJSONFull(pandocJSONFull,splits); //Splits input document along splits in an array of Pandoc-JSONs.

	var newDocs = findLinks(documentsArray); //returns array of Pandoc-JSONs with rewritten links and a string for filename.

	//console.log(JSON.stringify(newDocs[1]));
	/*
	try 1doc, 2doc as input for pandoc with
	pandoc -f json 1doc.json 1doc.html

	*/

	//new docs: array[n].doc array[n].doc array[n]filename
	newDocs.forEach(function(element, index, array){
		var process = "pandoc";
		var format = "html";
		var filename = element.filename;
		if (filename.length === 0){
			filename = "filename"+index;
		}
		var pandocArguments = ["--from json",("-o "+filename+".html")];
		var pandocify = JSON.stringify(element.doc);
		var whathappend = child_process.execSync('pandoc'+' '+pandocArguments.join(" "),{input:pandocify});
		console.log(whathappend);
	});

}).catch(function(reason){
	console.error(reason);
});

getSplitpoints = function(pandocJSONFull){
	//DOES: Finds chapter headlines and their indicies
	//GETS: pandoc JSON
	//RETURNS: an array of objects:
	// [
	// {mainindex ← the index of the headline in the pandoc JSON BLOCK array
	//  title ← the headline, stripped of non-word characters},
	//…]

	var splitPoints = [];
//array with objects {start:#, end#} for saving the node with the headline in the first, the node before the next headline in the second.
	pandocJSONFull.blocks.forEach(function(element, index, array){
		if (element.t === "Header" && element.c[0] == 1){//headline first order aka chapter
			splitPoints.push({
				"mainindex":index,
				"title":pandoc. //NOTE: Do I ever need th title? For the filenames and links, the title/filename is generated in the "findLinks" function
					stringify(element.c). //stringify makes a part of the tree to a simple string with no formatting
					replace(/\W/g, '') 	//Strips all non-word characters
								//TODO: what about öä etc.? "ae äé".replace(/\W/,"") strips "ä" but not "é"
			});
		}
	});

	if(splitPoints[0].mainindex>0){ //text starts not with a headline. Add fake splitpoint, so that begin will be included.
		splitPoints.unshift({mainindex:0,title:""});
	}
	return splitPoints;
};

splitPandocJSONFull = function(pandocJSONFull, splitPoints){
	//DOES: Splits the full PandocJSON in an array of chapter length PandocJSON Objects
	//GETS:
	//  pandocJSONFull: a PandocJSON of the full document
	//  splitPoints: an array  ob ojjects, each like
	// {mainindex ← the index of the headline in the pandoc JSON BLOCK array
	//  title ← the headline of the chapter, stripped of non-word characters}
	//
	//RETURNS: Array with Pandoc-JSONs, each a chapter of the original document
	var chapterArray = [];

	splitPoints.forEach(function(element, index, array){
		var startPoint=null,
			endPoint=null,
			chapter ={},
			chapterBlocks =[];

		startPoint = element.mainindex;

		if(index === array.length-1){ //last iteration
			endPoint = pandocJSONFull.blocks.length;//end with the last main Document element. NOT length-1 since the last node should be included in contrast to the next headline!
		} else{//all other iterations
			endPoint = array[index+1].mainindex;//end before next headline
		}

		//get the blocks of a chapter from the pandocJSON
		//NOTE: Array.slice does copy contained objects by reference. This is o.k. since we don’t want to have the same content twice in different documents.
		//REMEMBER: Array.slice copies up to, but not including, endPoint!
		chapterBlocks = pandocJSONFull.blocks.slice(startPoint, endPoint);

		//create a synthetic pandoc JSON object from the
		chapter={
			"meta": JSON.parse(JSON.stringify(pandocJSONFull.meta)), //sorta dirty trick to deep copy function-less objects: http://stackoverflow.com/a/122704/263398
			"blocks": chapterBlocks,
			"pandoc-api-version":JSON.parse(JSON.stringify(pandocJSONFull["pandoc-api-version"]))
		};

		chapterArray.push(chapter); //TODO
	});

	return chapterArray;
};

findLinks = function (documentsArray){ //finds internal links
	//DOES: rewrites all links in a pandocJSON which has internal links to external links if they link to another chapter.
	//GETS: array with pandocJSON documents.
	//RETURNS: array with pandocJSON documents with rewritten links.

	var rewrittenLinksArray = [];

	documentsArray.forEach(function(origDocument, index, array){
		rewrittenLinksArray[index]={};
		rewrittenLinksArray[index].filename = createDocumentFilename(documentsArray[index]);
		console.log("origDocument:\n \n ",origDocument,"|", index);
		rewrittenLinksArray[index].doc = pandoc.walk(
				origDocument,
				function(type,value,format,meta){
					//value[2][0] is the link target string
					if (type === "Link" && value[2][0].indexOf("#") === 0){// === sourceLinkId.slice(1)){
						var targetIndex = findTargetIndex(documentsArray,value[2][0]);

						if(typeof targetIndex !== "number"){
								return undefined; //no target found
						} else if (targetIndex === index) {
							return undefined;//internal link can stay. Target is in the same document
						} else {
							var filename = createDocumentFilename(documentsArray[targetIndex]);
							var newValue = value;
							//console.log("[",value[0],",",value[1],"]");

							//return pandoc.Link(value[0],value[1]);

							newValue[2][0] = filename+"."+format+value[2][0];//creates link to  OTHER document);
							console.log(newValue);
							return {t:'Link',c:newValue};
						}
					};//endif
				},"html",origDocument.meta);//find links
	});//end foreach
	return rewrittenLinksArray;
};//endfunction

createDocumentFilename = function(singleDocumentArray){
	//GETS: a pandocJSON
	//RETURNS: a filename for the document made of the Pandoc-JSON.
	var namestring;
	if(singleDocumentArray.blocks[0].t === "Header"){
		namestring = pandoc.stringify(singleDocumentArray.blocks[0].c).replace(/\W/g, '');//http://stackoverflow.com/questions/9364400/remove-not-alphanumeric-characters-from-string-having-trouble-with-the-char
	}else{
		namestring = pandoc.stringify(singleDocumentArray).slice(0,10).replace(/\W/g, ''); //this is rather inefficient to walk all the subtree (pandoc.stringify) to create a filename
	}

	return namestring;
};

//TODO check for using the pandoc generated identfiers for filenames too
findTargetIndex = function(documentsArray,sourceLinkId){ //
	// gets documents array and sourceLinkId,
	// returns the index of the document with the link target
	var targetDocumentIndex = null;

	documentsArray.forEach(function(element, index, array){
		pandoc.walk(
			element,
			function(type,value,format,meta){
				if (type === "Header" &&  value[1][0] === sourceLinkId.slice(1)){
					targetDocumentIndex = index;
					}//endif
					return undefined;
			},"html", element.meta);//end walk find targets
	});
	return 	targetDocumentIndex;
};
<|endoftext|>


<commit_before>var PushNotification = function() {
};

// Call this to register for push notifications. Content of [options] depends on whether we are working with APNS (iOS) or GCM (Android)
PushNotification.prototype.register = function(successCallback, errorCallback, options) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.register failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.register failure: success callback parameter must be a function");
        return
    }

    cordova.exec(successCallback, errorCallback, "PushPlugin", "register", [options]);
};

// Call this to unregister for push notifications
PushNotification.prototype.unregister = function(successCallback, errorCallback, options) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.unregister failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.unregister failure: success callback parameter must be a function");
        return
    }

     cordova.exec(successCallback, errorCallback, "PushPlugin", "unregister", [options]);
};

    // Call this if you want to show toast notification on WP8
    PushNotification.prototype.showToastNotification = function (successCallback, errorCallback, options) {
        if (errorCallback == null) { errorCallback = function () { } }

        if (typeof errorCallback != "function") {
            console.log("PushNotification.register failure: failure parameter not a function");
            return
        }

        cordova.exec(successCallback, errorCallback, "PushPlugin", "showToastNotification", [options]);
    }
// Call this to set the application icon badge
PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.setApplicationIconBadgeNumber failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.setApplicationIconBadgeNumber failure: success callback parameter must be a function");
        return
    }

    cordova.exec(successCallback, errorCallback, "PushPlugin", "setApplicationIconBadgeNumber", [{badge: badge}]);
};

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

if(!window.plugins) {
    window.plugins = {};
}
if (!window.plugins.pushNotification) {
    window.plugins.pushNotification = new PushNotification();
}

if (module.exports) {
  module.exports = PushNotification;
}<commit_msg>https://github.com/phonegap-build/PushPlugin/pull/142 (manual patch because fork is gone)<commit_after>var PushNotification = function() {
};

// Call this to register for push notifications. Content of [options] depends on whether we are working with APNS (iOS) or GCM (Android)
PushNotification.prototype.register = function(successCallback, errorCallback, options) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.register failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.register failure: success callback parameter must be a function");
        return
    }

    cordova.exec(successCallback, errorCallback, "PushPlugin", "register", [options]);
};

// Call this to unregister for push notifications
PushNotification.prototype.unregister = function(successCallback, errorCallback, options) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.unregister failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.unregister failure: success callback parameter must be a function");
        return
    }

     cordova.exec(successCallback, errorCallback, "PushPlugin", "unregister", [options]);
};

    // Call this if you want to show toast notification on WP8
    PushNotification.prototype.showToastNotification = function (successCallback, errorCallback, options) {
        if (errorCallback == null) { errorCallback = function () { } }

        if (typeof errorCallback != "function") {
            console.log("PushNotification.register failure: failure parameter not a function");
            return
        }

        cordova.exec(successCallback, errorCallback, "PushPlugin", "showToastNotification", [options]);
    }
// Call this to set the application icon badge
PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) {
    if (errorCallback == null) { errorCallback = function() {}}

    if (typeof errorCallback != "function")  {
        console.log("PushNotification.setApplicationIconBadgeNumber failure: failure parameter not a function");
        return
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.setApplicationIconBadgeNumber failure: success callback parameter must be a function");
        return
    }

    cordova.exec(successCallback, errorCallback, "PushPlugin", "setApplicationIconBadgeNumber", [{badge: badge}]);
};

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

if(!window.plugins) {
    window.plugins = {};
}
if (!window.plugins.pushNotification) {
    window.plugins.pushNotification = new PushNotification();
}

if (typeof module != 'undefined' && module.exports) {
  module.exports = PushNotification;
}<|endoftext|>


<commit_before>import {
  GraphQLList,
  GraphQLID,
  GraphQLNonNull
} from 'graphql';
import {Types} from 'mongoose';

import beerType from '../../types/beer';
import BeerModel from '../../../models/beer.model';

export default {
  type: beerType,
  args: {
    id: {
      name: 'id',
      type: new GraphQLNonNull(GraphQLID)
    }
  },
  resolve (root, params, ctx, options) {

    return BeerModel
      .findById(params.id)
      .exec();
  }
};
<commit_msg>quick fix: populate brewery on single beer<commit_after>import {
  GraphQLList,
  GraphQLID,
  GraphQLNonNull
} from 'graphql';
import {Types} from 'mongoose';

import beerType from '../../types/beer';
import BeerModel from '../../../models/beer.model';

export default {
  type: beerType,
  args: {
    id: {
      name: 'id',
      type: new GraphQLNonNull(GraphQLID)
    }
  },
  resolve (root, params, ctx, options) {

    return BeerModel
      .findById(params.id)
      .populate('brewery')
      .exec();
  }
};
<|endoftext|>


<commit_before>window.minTagID = ''

$(document).ready(function () {
  var tag = getTag()
  if (tag != '') {
    var grid = $('.grid')
    for (i = 0; i < 20; i++) {
      grid.append('\

 \

 \

 \

 \

 \

')
    }

    $("#tag").val(tag)
    getMedia(tag)
    // var timer = setInterval(function () { getMedia(tag) }, 2000)
  }
})

function getTag() {
  var url = window.location.href
  if(url.indexOf('=') < 0) return ''
  return window.location.href.split('=')[1]
}

function getMedia(tag) {
  $.getJSON("/media?tag=" + tag + '&min_tag_id=' + window.minTagID, function (data) {
    if (data.data.length > 0) {
      window.minTagID = data.pagination.min_tag_id
    }
    var data = data.data
    console.log(data)
    for(i = 0; i < data.length; i++) {
      var item = $('#index_' + i)
      item.css({
        'background-image': 'url(' + data[i].images.standard_resolution.url + ')'
      })
      item.find('.photo').css({
        'background-image': 'url(' + data[i].user.profile_picture + ')'
      })
      item.find('.text').html(data[i].caption.text)
    }
  })
}
<commit_msg>Live updating<commit_after>window.minTagID = ''

$(document).ready(function () {
  var tag = getTag()
  if (tag != '') {
    var grid = $('.grid')
    for (i = 0; i < 20; i++) {
      grid.append('

')
    }

    $("#tag").val(tag)
    getMedia(tag)
    var timer = setInterval(function () { getMedia(tag) }, 2000)
  }
})

function getTag() {
  var url = window.location.href
  if(url.indexOf('=') < 0) return ''
  return window.location.href.split('=')[1]
}

function getMedia(tag) {
  $.getJSON("/media?tag=" + tag + '&min_tag_id=' + window.minTagID, function (data) {
    if (data.data.length > 0) {
      window.minTagID = data.pagination.min_tag_id
    }
    var data = data.data
    var indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
    indices = shuffle(indices)
    for(i = 0; i < data.length; i++) {
      var item = $('#index_' + indices[i])
      item.css({
        'background-image': 'url(' + data[i].images.standard_resolution.url + ')'
      })
    }
  })
}

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex ;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
<|endoftext|>