<commit_before>// ### Search
//
// lookup for saved searches
/*jslint browser: true */
/*jslint node: true */
/* global $,alert,doQuery */
'use strict';

var savedSearches, sbUser = window.senseBase.user.username;
var pubsub = require('./pubsub');

exports.init = function(resultsLib) {
  // set team input as select2 input
  $('.team.container').select2();

  // schedule search
  $('.schedule.button').click(function() {
    setupCronInput();
    $('.schedule.modal').modal('show');
    $('.cron.edit').html('');
  });

  // show search scheduler according to checkbox
  $('#scheduleSearch').on('change', function() {
    $('#scheduleInput').toggle(this.checked);
  });

  $('input.cron').val();

  // setup semantic-ui form validation
  $('.searching.form').form(
    {
      searchInput: {
        identifier  : 'searchInput',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter member input'
          }
        ]
      },
      searchCategories: {
        identifier : 'searchCategories',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter one or more comma-seperated categories'
          }
        ]
      },
      searchTeam: {
        identifier : 'searchTeam',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter one or more members'
          }
        ]
      }
    },
    {
      onSuccess: submitSearch
    }
  );

  pubsub.subSearches(function(results) {
    savedSearches = results;
    if (results && results.hits.total > 0) {
      $("#loadSearch").select2({
        data: results.hits.hits.map(function(i) { return { id: i._source.searchName, text: i._source.searchName }; })
      });
      $('.load.search').attr('disabled', false);
    } else {
      $('.load.search').attr('disabled', true);
    }
  });

  // save a search
  $('.save.search').click(function() {
    var searchInput = getSearchInput();
    if (searchInput.valid && searchInput.searchName.length > 0) {
      pubsub.searchSave(searchInput);
    } else {
      alert('Missing parameters');
    }
  });

  // display saved searches
  $('.load.search').click(function() {
    $('.load.modal').modal('show');
  });

  // load a search
  $('button.search.load').click(function() {
    var v = $('#loadSearch').val();
    savedSearches.hits.hits.forEach(function(s) {
      if (s._source.searchName === v) {
        var r = s._source;
        if (r.cron) {
          $('input.cron').val(r.cron);
          $('#scheduleSearch').prop('checked', true);
        } else {
          $('#scheduleSearch').prop('checked', false);
        }
        setupCronInput(r.cron);
        $('#scheduleSearch').trigger('change');
        $('#searchName').val(v);
        $('#targetResults').val(r.targetResults);
        $('#searchInput').val(r.input);
        $('#searchContinue').val(r.relevance);
        $('#searchCategories').val(r.categories);
        $('select.searching.team').val(r.team);
        $('.team.container').select2('val', r.team);
        return;
      }
    });
  });
  // set up the cron scheduler input
  function setupCronInput(val) {
    $('input.cron').jqCron({
      enabled_minute: false,
      multiple_dom: true,
      multiple_month: true,
      multiple_mins: true,
      multiple_dow: true,
      multiple_time_hours: true,
      multiple_time_minutes: true,
      default_period: 'week',
      default_value: val || '15 12 * * 7',
      no_reset_button: true,
      lang: 'en'
    });
  }

  // convert the form values to data
  function getSearchInput() {
    var cronValue = $('#scheduleSearch').prop('checked') ? $('input.cron').val() : null, searchName = $('#searchName').val(), targetResults = $('#targetResults').val(), input = $('#searchInput').val(), searchContinue = $('#searchContinue').val(), searchCategories = $('#searchCategories').val().split(',').map(function(t) { return t.trim(); }), searchTeam = $('select.searching.team option:selected').map(function() { return this.value; }).get();
    return { searchName: searchName, cron: cronValue, input: input, relevance: searchContinue, team: searchTeam, categories: searchCategories, member: sbUser, targetResults: targetResults, valid: (input.length > 0 && searchContinue.length > 0 && searchTeam.length > 0 && searchCategories.length > 0 && sbUser.length > 0 && targetResults.length > 0 )};
  }

  // submit a new search
  function submitSearch() {
    var searchInput = getSearchInput();
    // FIXME: SUI validation for select2 field
      if (!searchInput.valid) {
      alert('Please select team members');
      return;
    }
    console.log('publishing', searchInput);
    pubsub.searchQueue(searchInput);
    if ($('#refreshSearch').prop('checked')) {
      $('#annoSearch').val($('#searchCategories').val());
    //  $('#validationState').val('queued');
      $('#refreshQueries').prop('checked', true);
      resultsLib.setupQueryRefresher(5000);
    }
    doQuery();
  }

};
<commit_msg>fix username<commit_after>// ### Search
//
// lookup for saved searches
/*jslint browser: true */
/*jslint node: true */
/* global $,alert,doQuery */
'use strict';

var savedSearches, sbUser = window.senseBase.user;
var pubsub = require('./pubsub');

exports.init = function(resultsLib) {
  // set team input as select2 input
  $('.team.container').select2();

  // schedule search
  $('.schedule.button').click(function() {
    setupCronInput();
    $('.schedule.modal').modal('show');
    $('.cron.edit').html('');
  });

  // show search scheduler according to checkbox
  $('#scheduleSearch').on('change', function() {
    $('#scheduleInput').toggle(this.checked);
  });

  $('input.cron').val();

  // setup semantic-ui form validation
  $('.searching.form').form(
    {
      searchInput: {
        identifier  : 'searchInput',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter member input'
          }
        ]
      },
      searchCategories: {
        identifier : 'searchCategories',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter one or more comma-seperated categories'
          }
        ]
      },
      searchTeam: {
        identifier : 'searchTeam',
        rules: [
          {
            type   : 'empty',
            prompt : 'Please enter one or more members'
          }
        ]
      }
    },
    {
      onSuccess: submitSearch
    }
  );

  pubsub.subSearches(function(results) {
    savedSearches = results;
    if (results && results.hits.total > 0) {
      $("#loadSearch").select2({
        data: results.hits.hits.map(function(i) { return { id: i._source.searchName, text: i._source.searchName }; })
      });
      $('.load.search').attr('disabled', false);
    } else {
      $('.load.search').attr('disabled', true);
    }
  });

  // save a search
  $('.save.search').click(function() {
    var searchInput = getSearchInput();
    if (searchInput.valid && searchInput.searchName.length > 0) {
      pubsub.searchSave(searchInput);
    } else {
      alert('Missing parameters');
    }
  });

  // display saved searches
  $('.load.search').click(function() {
    $('.load.modal').modal('show');
  });

  // load a search
  $('button.search.load').click(function() {
    var v = $('#loadSearch').val();
    savedSearches.hits.hits.forEach(function(s) {
      if (s._source.searchName === v) {
        var r = s._source;
        if (r.cron) {
          $('input.cron').val(r.cron);
          $('#scheduleSearch').prop('checked', true);
        } else {
          $('#scheduleSearch').prop('checked', false);
        }
        setupCronInput(r.cron);
        $('#scheduleSearch').trigger('change');
        $('#searchName').val(v);
        $('#targetResults').val(r.targetResults);
        $('#searchInput').val(r.input);
        $('#searchContinue').val(r.relevance);
        $('#searchCategories').val(r.categories);
        $('select.searching.team').val(r.team);
        $('.team.container').select2('val', r.team);
        return;
      }
    });
  });
  // set up the cron scheduler input
  function setupCronInput(val) {
    $('input.cron').jqCron({
      enabled_minute: false,
      multiple_dom: true,
      multiple_month: true,
      multiple_mins: true,
      multiple_dow: true,
      multiple_time_hours: true,
      multiple_time_minutes: true,
      default_period: 'week',
      default_value: val || '15 12 * * 7',
      no_reset_button: true,
      lang: 'en'
    });
  }

  // convert the form values to data
  function getSearchInput() {
    var cronValue = $('#scheduleSearch').prop('checked') ? $('input.cron').val() : null, searchName = $('#searchName').val(), targetResults = $('#targetResults').val(), input = $('#searchInput').val(), searchContinue = $('#searchContinue').val(), searchCategories = $('#searchCategories').val().split(',').map(function(t) { return t.trim(); }), searchTeam = $('select.searching.team option:selected').map(function() { return this.value; }).get();
    return { searchName: searchName, cron: cronValue, input: input, relevance: searchContinue, team: searchTeam, categories: searchCategories, member: sbUser, targetResults: targetResults, valid: (input.length > 0 && searchContinue.length > 0 && searchTeam.length > 0 && searchCategories.length > 0 && sbUser.length > 0 && targetResults.length > 0 )};
  }

  // submit a new search
  function submitSearch() {
    var searchInput = getSearchInput();
    // FIXME: SUI validation for select2 field
      if (!searchInput.valid) {
      alert('Please select team members');
      return;
    }
    console.log('publishing', searchInput);
    pubsub.searchQueue(searchInput);
    if ($('#refreshSearch').prop('checked')) {
      $('#annoSearch').val($('#searchCategories').val());
    //  $('#validationState').val('queued');
      $('#refreshQueries').prop('checked', true);
      resultsLib.setupQueryRefresher(5000);
    }
    doQuery();
  }

};
<|endoftext|>


<commit_before>/* plugger.js: allows plugs to have an api into the nifty collaboration engine.
 * Copyright © 2011 Thaddee Tyl, Jan Keromnes. All rights reserved.
 * The following code is covered by the GPLv2 license. */

(function () {

var debug = true;
// IE doesn't have a console, but we avoid a crash thanks to this.
//alert(window.console);
var console = (window.console && debug)? window.console: {
  log: function(){
    for (var arg in arguments)
      console.data = (console.data?console.data:'') + arg + ' ';
    console.data += '\n';
  }
};

// We need all the power of diff, match and patch.
var dmp = new diff_match_patch ();

///  Application Programming Interface.
//

// Information we keep on the state of the content of the editor.
window.client = {
  user: +(new Date()),
  lastcopy: '',
  path: ''          // name of the path to the file.
};

var plug = {
  newcontent: function (content) {
    // Here, we consider the differences between current text
    // and the text we had last time we pushed changes.

    // Create the patch that we want to send to the wire.
    var newdiff = dmp.diff_main (client.lastcopy, content);
    if (newdiff.length > 2) {
      dmp.diff_cleanupSemantic (newdiff);
      dmp.diff_cleanupEfficiency (newdiff);
    }

    // Send back the new diff if there is something to it.
    if (newdiff.length !== 1 || newdiff[0][0] !== DIFF_EQUAL) {

      if (acked) {
        // Update the last copy.
        client.lastcopy = content;

        // Send the new diff.
        Scout.send (sending (decodeURI(dmp.diff_toDelta (newdiff))
              .replace ('%','%25'))) ();

        acked = false;
      } else {
        console.error('not acked');
        resend = true;
      }
    }
  }
};

var giveplug = function (path, onnewcontent, onnewdiff) {
  if (onnewcontent) {
    plug.onnewcontent = onnewcontent;
    plug.onnewdiff = onnewdiff;
  }
  client.path = path;
  getdata();
  return plug;
};

///  Synchronization components.
//

// client: { lastcopy: 'content before last sync' }
// delta: patch (in delta form) to apply to our copy.
// applylocally: function ( patch ) { return newWorkingCopy; }
// send: function ( delta ) { }
function sync (client, delta, applylocally, send) {

  // Patch last copy.
  // Note: dmp.patch_apply returns the resulting text in the first element
  // of the array.
  var lastcopydiff = dmp.diff_fromDelta (client.lastcopy, delta);
  var lastcopypatch = dmp.patch_make (client.lastcopy, lastcopydiff);
  client.lastcopy = dmp.patch_apply (lastcopypatch, client.lastcopy) [0];

  // Patch working copy.
  var workingcopy = applylocally (lastcopypatch);

  // Create the patch that we want to send to the wire.
  var newdiff = dmp.diff_main (client.lastcopy, workingcopy);
  if (newdiff.length > 2) {
    dmp.diff_cleanupSemantic (newdiff);
    dmp.diff_cleanupEfficiency (newdiff);
  }

  // Update the last copy.
  client.lastcopy = workingcopy;

  // Send back the new diff if there is something to it.
  if (newdiff.length !== 1 || newdiff[0][0] !== DIFF_EQUAL) {
    // Send the new delta.
    send (decodeURI (dmp.diff_toDelta (newdiff)).replace('%','%25'));
  }
}

//1. This place is specifically designed to receive information from the server.

// Whenever we load the page, we shall send nothing to
// the "dispatch" channel of the server.
Scout.EventSource('dispatch').onrecv(function (resp) {
  console.log ('received', resp);

  // If it is us, we have already done the modification.
  if (resp.user === client.user) return;

  // We sync it to our copy.
  sync (client, resp.delta, function applylocally(patch) {
    // Get what our content should look like after this function runs.
    var futurecontent = dmp.patch_apply (patch, client.copy) [0];
    // Figure out the difference w.r.t our working copy.
    var change = dmp.diff_main (client.copy, futurecontent);

    // Consult plug.
    client.copy = (plug.onnewdiff? plug.onnewdiff (change):
      plug.onnewcontent (futurecontent));

    return client.copy;
  }, function sendnewdelta (delta) {
    Scout.send (sending (delta)) ();
  });
});

//2. This place is specifically designed to send information to the server.

var acked = true,
    resend = false;

// We want to listen to the event of code modification.
function sending (delta) {
  return function fsending (params) {

    // If there was no modification, we do not do anything.
    if (delta.length === 0) { return; }

    params.data = {
      user: client.user,
      path: client.path,
      delta: delta
    };

    params.action = 'new';

    // DEBUG
    console.log('sending: ' + JSON.stringify(params.data));
    params.resp = function () {
      console.log ('sent');
      acked = true;
      if (resend) {
        console.log('resending now!');
        resend = false;
        plug.newcontent(plug.onnewdiff([]));
      }
    };

    params.error = function senderror (status) {
      console.log('send error: status', JSON.stringify(status));
    };

  };
}

//3. This place handles getting it all the first time... and death.

// Get the data.
// WARNING: If there's a delay with codemirror, this might cause a problem.
// Best is to place this call in an onLoad function.
function getdata() {
  Scout.send (function (params) {
    params.action = 'data';
    params.data = {user:client.user, path:client.path};
    params.resp = function (resp) {
      console.log ('got content');///

      client.copy = client.lastcopy = resp.data;
      plug.onnewcontent (client.copy);
    };
  }) ();
}

//// When we leave, tell the server.
//window.onunload = function () {
//  Scout.send (function (params) {
//    params.action = 'kill';
//    params.data = {user:client.user, path:client.path};
//  }) ();
//};

///  Exports.
//

//   getplug ( onnewcontent, onnewdiff )
//
// The onnewcontent ( content ) function is fired every time there is new
// content, and we need to clean all content up.
// The optional onnewdiff ( diff ) function is fired when there is new content
// to take into account, and the onnewdiff function exists.
// Those functions must both return the current content of the data.
//
// The result has a method newcontent ( content ) that sends the new content to
// the server.
//
window.getplug = giveplug;

}) ();
<commit_msg>Updated plugger.js to match newest ScoutCamp.<commit_after>/* plugger.js: allows plugs to have an api into the nifty collaboration engine.
 * Copyright © 2011 Thaddee Tyl, Jan Keromnes. All rights reserved.
 * The following code is covered by the GPLv2 license. */

(function () {

var debug = true;
// IE doesn't have a console, but we avoid a crash thanks to this.
//alert(window.console);
var console = (window.console && debug)? window.console: {
  log: function(){
    for (var arg in arguments)
      console.data = (console.data?console.data:'') + arg + ' ';
    console.data += '\n';
  }
};

// We need all the power of diff, match and patch.
var dmp = new diff_match_patch ();

///  Application Programming Interface.
//

// Information we keep on the state of the content of the editor.
window.client = {
  user: +(new Date()),
  lastcopy: '',
  path: ''          // name of the path to the file.
};

var plug = {
  newcontent: function (content) {
    // Here, we consider the differences between current text
    // and the text we had last time we pushed changes.

    // Create the patch that we want to send to the wire.
    var newdiff = dmp.diff_main (client.lastcopy, content);
    if (newdiff.length > 2) {
      dmp.diff_cleanupSemantic (newdiff);
      dmp.diff_cleanupEfficiency (newdiff);
    }

    // Send back the new diff if there is something to it.
    if (newdiff.length !== 1 || newdiff[0][0] !== DIFF_EQUAL) {

      if (acked) {
        // Update the last copy.
        client.lastcopy = content;

        // Send the new diff.
        Scout.send (sending (decodeURI(dmp.diff_toDelta (newdiff))
              .replace ('%','%25'))) ();

        acked = false;
      } else {
        console.error('not acked');
        resend = true;
      }
    }
  }
};

var giveplug = function (path, onnewcontent, onnewdiff) {
  if (onnewcontent) {
    plug.onnewcontent = onnewcontent;
    plug.onnewdiff = onnewdiff;
  }
  client.path = path;
  getdata();
  return plug;
};

///  Synchronization components.
//

// client: { lastcopy: 'content before last sync' }
// delta: patch (in delta form) to apply to our copy.
// applylocally: function ( patch ) { return newWorkingCopy; }
// send: function ( delta ) { }
function sync (client, delta, applylocally, send) {

  // Patch last copy.
  // Note: dmp.patch_apply returns the resulting text in the first element
  // of the array.
  var lastcopydiff = dmp.diff_fromDelta (client.lastcopy, delta);
  var lastcopypatch = dmp.patch_make (client.lastcopy, lastcopydiff);
  client.lastcopy = dmp.patch_apply (lastcopypatch, client.lastcopy) [0];

  // Patch working copy.
  var workingcopy = applylocally (lastcopypatch);

  // Create the patch that we want to send to the wire.
  var newdiff = dmp.diff_main (client.lastcopy, workingcopy);
  if (newdiff.length > 2) {
    dmp.diff_cleanupSemantic (newdiff);
    dmp.diff_cleanupEfficiency (newdiff);
  }

  // Update the last copy.
  client.lastcopy = workingcopy;

  // Send back the new diff if there is something to it.
  if (newdiff.length !== 1 || newdiff[0][0] !== DIFF_EQUAL) {
    // Send the new delta.
    send (decodeURI (dmp.diff_toDelta (newdiff)).replace('%','%25'));
  }
}

//1. This place is specifically designed to receive information from the server.

// Whenever we load the page, we shall send nothing to
// the "dispatch" channel of the server.
Scout.eventSource('dispatch').onrecv(function (resp) {
  console.log ('received', resp);

  // If it is us, we have already done the modification.
  if (resp.user === client.user) return;

  // We sync it to our copy.
  sync (client, resp.delta, function applylocally(patch) {
    // Get what our content should look like after this function runs.
    var futurecontent = dmp.patch_apply (patch, client.copy) [0];
    // Figure out the difference w.r.t our working copy.
    var change = dmp.diff_main (client.copy, futurecontent);

    // Consult plug.
    client.copy = (plug.onnewdiff? plug.onnewdiff (change):
      plug.onnewcontent (futurecontent));

    return client.copy;
  }, function sendnewdelta (delta) {
    Scout.send (sending (delta)) ();
  });
});

//2. This place is specifically designed to send information to the server.

var acked = true,
    resend = false;

// We want to listen to the event of code modification.
function sending (delta) {
  return function fsending (params) {

    // If there was no modification, we do not do anything.
    if (delta.length === 0) { return; }

    params.data = {
      user: client.user,
      path: client.path,
      delta: delta
    };

    params.action = 'new';

    // DEBUG
    console.log('sending: ' + JSON.stringify(params.data));
    params.resp = function () {
      console.log ('sent');
      acked = true;
      if (resend) {
        console.log('resending now!');
        resend = false;
        plug.newcontent(plug.onnewdiff([]));
      }
    };

    params.error = function senderror (status) {
      console.log('send error: status', JSON.stringify(status));
    };

  };
}

//3. This place handles getting it all the first time... and death.

// Get the data.
// WARNING: If there's a delay with codemirror, this might cause a problem.
// Best is to place this call in an onLoad function.
function getdata() {
  Scout.send (function (params) {
    params.action = 'data';
    params.data = {user:client.user, path:client.path};
    params.resp = function (resp) {
      console.log ('got content');///

      client.copy = client.lastcopy = resp.data;
      plug.onnewcontent (client.copy);
    };
  }) ();
}

//// When we leave, tell the server.
//window.onunload = function () {
//  Scout.send (function (params) {
//    params.action = 'kill';
//    params.data = {user:client.user, path:client.path};
//  }) ();
//};

///  Exports.
//

//   getplug ( onnewcontent, onnewdiff )
//
// The onnewcontent ( content ) function is fired every time there is new
// content, and we need to clean all content up.
// The optional onnewdiff ( diff ) function is fired when there is new content
// to take into account, and the onnewdiff function exists.
// Those functions must both return the current content of the data.
//
// The result has a method newcontent ( content ) that sends the new content to
// the server.
//
window.getplug = giveplug;

}) ();
<|endoftext|>


<commit_before>/* eslint-disable import/no-dynamic-require*/
const resources = require('./resources.js');
const express = require('express');
const cons = require('consolidate');
const pg = require('pg');
const raven = require('raven');

const app = express();

const dbconfigfile = require(`${__dirname}/../../database.json`);
const dbconfig = dbconfigfile.dev;

// use NODE_ENV for defining which asset urls to use
let assetsJS = 'http://localhost:3000/app.js';
let assetsCSS = 'http://localhost:3000/app.css';
if (process.env.NODE_ENV === 'production') {
    assetsJS = '/app.js';
    assetsCSS = '/app.css';
}
console.info('nodeENV', process.env.NODE_ENV);

let buildInfo = {};
try {
    const fileName = `${__dirname}/../../buildinfo.json`;
    if (require.resolve(fileName)) {
        // eslint-disable-next-line global-require
        buildInfo = require(fileName);
    }
// eslint-disable-next-line no-empty
} catch (e) {}

// raven configuration
let sentryClient;
if (process.env.SENTRY_TOKEN) {
    sentryClient = new raven.Client(process.env.SENTRY_TOKEN, {
        release: buildInfo.git || '',
        environment: process.env.NODE_ENV,
    });
    sentryClient.patchGlobal();
}

console.info('Sentry', !sentryClient ? 'disabled' : 'enabled');

app.engine('html', cons.mustache);
app.set('view engine', 'html');
app.set('views', `${__dirname}/../../views`);
app.set('sentry_client', sentryClient);

app.set('pg', (fn) => {
    pg.connect(dbconfig, (err, client, done) => {
        if (err) {
            return console.error('failed to retrieve client from pool');
        }
        fn(client);
        done();
        return true;
    });
});

app.use('/api', resources.api);

app.use(express.static(`${__dirname}/../../public`));

app.all(/.*/, (req, res) => {
    res.render('index', { css: assetsCSS, js: assetsJS, build: JSON.stringify(buildInfo) }, (err, html) => {
        if (err) {
            res.status(500).send('Internal Server Error').end();
        }
        res.send(html).end();
    });
});

const port = process.env.PORT || 8080;
app.listen(port);

console.info(`listening on port ${port}...`);

process.on('SIGINT', () => {
    process.exit();
});
<commit_msg>adjust logic to be more sane<commit_after>/* eslint-disable import/no-dynamic-require*/
const resources = require('./resources.js');
const express = require('express');
const cons = require('consolidate');
const pg = require('pg');
const raven = require('raven');

const app = express();

const dbconfigfile = require(`${__dirname}/../../database.json`);
const dbconfig = dbconfigfile.dev;

// use NODE_ENV for defining which asset urls to use
let assetsJS = 'http://localhost:3000/app.js';
let assetsCSS = 'http://localhost:3000/app.css';
if (process.env.NODE_ENV === 'production') {
    assetsJS = '/app.js';
    assetsCSS = '/app.css';
}
console.info('nodeENV', process.env.NODE_ENV);

let buildInfo = {};
try {
    const fileName = `${__dirname}/../../buildinfo.json`;
    if (require.resolve(fileName)) {
        // eslint-disable-next-line global-require
        buildInfo = require(fileName);
    }
// eslint-disable-next-line no-empty
} catch (e) {}

// raven configuration
let sentryClient;
if (process.env.SENTRY_TOKEN) {
    sentryClient = new raven.Client(process.env.SENTRY_TOKEN, {
        release: buildInfo.git || '',
        environment: process.env.NODE_ENV,
    });
    sentryClient.patchGlobal();
}

console.info('Sentry', sentryClient ? 'enabled' : 'disabled');

app.engine('html', cons.mustache);
app.set('view engine', 'html');
app.set('views', `${__dirname}/../../views`);
app.set('sentry_client', sentryClient);

app.set('pg', (fn) => {
    pg.connect(dbconfig, (err, client, done) => {
        if (err) {
            return console.error('failed to retrieve client from pool');
        }
        fn(client);
        done();
        return true;
    });
});

app.use('/api', resources.api);

app.use(express.static(`${__dirname}/../../public`));

app.all(/.*/, (req, res) => {
    res.render('index', { css: assetsCSS, js: assetsJS, build: JSON.stringify(buildInfo) }, (err, html) => {
        if (err) {
            res.status(500).send('Internal Server Error').end();
        }
        res.send(html).end();
    });
});

const port = process.env.PORT || 8080;
app.listen(port);

console.info(`listening on port ${port}...`);

process.on('SIGINT', () => {
    process.exit();
});
<|endoftext|>


<commit_before>import {inject} from 'aurelia-dependency-injection';
import {DOM} from 'aurelia-pal';
import {_isAllWhitespace} from './util';

let noNodes = Object.freeze([]);

@inject(DOM.Element)
export class SlotCustomAttribute {
  constructor(element) {
    this.element = element;
    this.element.auSlotAttribute = this;
  }

  valueChanged(newValue, oldValue) {
    //console.log('au-slot', newValue);
  }
}

export class PassThroughSlot {
  constructor(anchor, name, destinationName, fallbackFactory) {
    this.anchor = anchor;
    this.anchor.viewSlot = this;
    this.name = name;
    this.destinationName = destinationName;
    this.fallbackFactory = fallbackFactory;
    this.destinationSlot = null;
    this.projections = 0;
    this.contentView = null;

    let attr = new SlotCustomAttribute(this.anchor);
    attr.value = this.destinationName;
  }

  get needsFallbackRendering() {
    return this.fallbackFactory && this.projections === 0;
  }

  renderFallbackContent(view, nodes, projectionSource, index) {
    if (this.contentView === null) {
      this.contentView = this.fallbackFactory.create(this.ownerView.container);
      this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);

      let slots = Object.create(null);
      slots[this.destinationSlot.name] = this.destinationSlot;

      ShadowDOM.distributeView(this.contentView, slots, projectionSource, index, this.destinationSlot.name);
    }
  }

  passThroughTo(destinationSlot) {
    this.destinationSlot = destinationSlot;
  }

  addNode(view, node, projectionSource, index) {
    if (this.contentView !== null) {
      this.contentView.removeNodes();
      this.contentView.detached();
      this.contentView.unbind();
      this.contentView = null;
    }

    if (node.viewSlot instanceof PassThroughSlot) {
      node.viewSlot.passThroughTo(this);
      return;
    }

    this.projections++;
    this.destinationSlot.addNode(view, node, projectionSource, index);
  }

  removeView(view, projectionSource) {
    this.projections--;
    this.destinationSlot.removeView(view, projectionSource);

    if (this.needsFallbackRendering) {
      this.renderFallbackContent(null, noNodes, projectionSource);
    }
  }

  removeAll(projectionSource) {
    this.projections = 0;
    this.destinationSlot.removeAll(projectionSource);

    if (this.needsFallbackRendering) {
      this.renderFallbackContent(null, noNodes, projectionSource);
    }
  }

  projectFrom(view, projectionSource) {
    this.destinationSlot.projectFrom(view, projectionSource);
  }

  created(ownerView) {
    this.ownerView = ownerView;
  }

  bind(view) {
    if (this.contentView) {
      this.contentView.bind(view.bindingContext, view.overrideContext);
    }
  }

  attached() {
    if (this.contentView) {
      this.contentView.attached();
    }
  }

  detached() {
    if (this.contentView) {
      this.contentView.detached();
    }
  }

  unbind() {
    if (this.contentView) {
      this.contentView.unbind();
    }
  }
}

export class ShadowSlot {
  constructor(anchor, name, fallbackFactory) {
    this.anchor = anchor;
    this.anchor.isContentProjectionSource = true;
    this.anchor.viewSlot = this;
    this.name = name;
    this.fallbackFactory = fallbackFactory;
    this.contentView = null;
    this.projections = 0;
    this.children = [];
    this.projectFromAnchors = null;
    this.destinationSlots = null;
  }

  get needsFallbackRendering() {
    return this.fallbackFactory && this.projections === 0;
  }

  addNode(view, node, projectionSource, index, destination) {
    if (this.contentView !== null) {
      this.contentView.removeNodes();
      this.contentView.detached();
      this.contentView.unbind();
      this.contentView = null;
    }

    if (node.viewSlot instanceof PassThroughSlot) {
      node.viewSlot.passThroughTo(this);
      return;
    }

    if (this.destinationSlots !== null) {
      ShadowDOM.distributeNodes(view, [node], this.destinationSlots, this, index);
    } else {
      node.auOwnerView = view;
      node.auProjectionSource = projectionSource;
      node.auAssignedSlot = this;

      let anchor = this._findAnchor(view, node, projectionSource, index);
      let parent = anchor.parentNode;

      parent.insertBefore(node, anchor);
      this.children.push(node);
      this.projections++;
    }
  }

  removeView(view, projectionSource) {
    if (this.destinationSlots !== null) {
      ShadowDOM.undistributeView(view, this.destinationSlots, this);
    } else if (this.contentView && this.contentView.hasSlots) {
      ShadowDOM.undistributeView(view, this.contentView.slots, projectionSource);
    } else {
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
      if (found) {
        let children = found.auProjectionChildren;

        for (let i = 0, ii = children.length; i < ii; ++i) {
          let child = children[i];

          if (child.auOwnerView === view) {
            children.splice(i, 1);
            view.fragment.appendChild(child);
            i--; ii--;
            this.projections--;
          }
        }

        if (this.needsFallbackRendering) {
          this.renderFallbackContent(view, noNodes, projectionSource);
        }
      }
    }
  }

  removeAll(projectionSource) {
    if (this.destinationSlots !== null) {
      ShadowDOM.undistributeAll(this.destinationSlots, this);
    } else if (this.contentView && this.contentView.hasSlots) {
      ShadowDOM.undistributeAll(this.contentView.slots, projectionSource);
    } else {
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);

      if (found) {
        let children = found.auProjectionChildren;
        for (let i = 0, ii = children.length; i < ii; ++i) {
          let child = children[i];
          child.auOwnerView.fragment.appendChild(child);
          this.projections--;
        }

        found.auProjectionChildren = [];

        if (this.needsFallbackRendering) {
          this.renderFallbackContent(null, noNodes, projectionSource);
        }
      }
    }
  }

  _findAnchor(view, node, projectionSource, index) {
    if (projectionSource) {
      //find the anchor associated with the projected view slot
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
      if (found) {
        if (index !== undefined) {
          let children = found.auProjectionChildren;
          let viewIndex = -1;
          let lastView;

          for (let i = 0, ii = children.length; i < ii; ++i) {
            let current = children[i];

            if (current.auOwnerView !== lastView) {
              viewIndex++;
              lastView = current.auOwnerView;

              if (viewIndex >= index && lastView !== view) {
                children.splice(i, 0, node);
                return current;
              }
            }
          }
        }

        found.auProjectionChildren.push(node);
        return found;
      }
    }

    return this.anchor;
  }

  projectTo(slots) {
    this.destinationSlots = slots;
  }

  projectFrom(view, projectionSource) {
    let anchor = DOM.createComment('anchor');
    let parent = this.anchor.parentNode;
    anchor.auSlotProjectFrom = projectionSource;
    anchor.auOwnerView = view;
    anchor.auProjectionChildren = [];
    parent.insertBefore(anchor, this.anchor);
    this.children.push(anchor);

    if (this.projectFromAnchors === null) {
      this.projectFromAnchors = [];
    }

    this.projectFromAnchors.push(anchor);
  }

  renderFallbackContent(view, nodes, projectionSource, index) {
    if (this.contentView === null) {
      this.contentView = this.fallbackFactory.create(this.ownerView.container);
      this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);
      this.contentView.insertNodesBefore(this.anchor);
    }

    if (this.contentView.hasSlots) {
      let slots = this.contentView.slots;
      let projectFromAnchors = this.projectFromAnchors;

      if (projectFromAnchors !== null) {
        for (let slotName in slots) {
          let slot = slots[slotName];

          for (let i = 0, ii = projectFromAnchors.length; i < ii; ++i) {
            let anchor = projectFromAnchors[i];
            slot.projectFrom(anchor.auOwnerView, anchor.auSlotProjectFrom);
          }
        }
      }

      this.fallbackSlots = slots;
      ShadowDOM.distributeNodes(view, nodes, slots, projectionSource, index);
    }
  }

  created(ownerView) {
    this.ownerView = ownerView;
  }

  bind(view) {
    if (this.contentView) {
      this.contentView.bind(view.bindingContext, view.overrideContext);
    }
  }

  attached() {
    if (this.contentView) {
      this.contentView.attached();
    }
  }

  detached() {
    if (this.contentView) {
      this.contentView.detached();
    }
  }

  unbind() {
    if (this.contentView) {
      this.contentView.unbind();
    }
  }
}

export class ShadowDOM {
  static defaultSlotKey = '__au-default-slot-key__';

  static getSlotName(node) {
    if (node.auSlotAttribute === undefined) {
      return ShadowDOM.defaultSlotKey;
    }

    return node.auSlotAttribute.value;
  }

  static distributeView(view, slots, projectionSource, index, destinationOverride) {
    let nodes;

    if (view === null) {
      nodes = noNodes;
    } else {
      let childNodes = view.fragment.childNodes;
      let ii = childNodes.length;
      nodes = new Array(ii);

      for (let i = 0; i < ii; ++i) {
        nodes[i] = childNodes[i];
      }
    }

    ShadowDOM.distributeNodes(
      view,
      nodes,
      slots,
      projectionSource,
      index,
      destinationOverride
    );
  }

  static undistributeView(view, slots, projectionSource) {
    for (let slotName in slots) {
      slots[slotName].removeView(view, projectionSource);
    }
  }

  static undistributeAll(slots, projectionSource) {
    for (let slotName in slots) {
      slots[slotName].removeAll(projectionSource);
    }
  }

  static distributeNodes(view, nodes, slots, projectionSource, index, destinationOverride) {
    for (let i = 0, ii = nodes.length; i < ii; ++i) {
      let currentNode = nodes[i];
      let nodeType = currentNode.nodeType;

      if (currentNode.isContentProjectionSource) {
        currentNode.viewSlot.projectTo(slots);

        for (let slotName in slots) {
          slots[slotName].projectFrom(view, currentNode.viewSlot);
        }

        nodes.splice(i, 1);
        ii--; i--;
      } else if (nodeType === 1 || nodeType === 3 || currentNode.viewSlot instanceof PassThroughSlot) { //project only elements and text
        if (nodeType === 3 && _isAllWhitespace(currentNode)) {
          nodes.splice(i, 1);
          ii--; i--;
        } else {
          let found = slots[destinationOverride || ShadowDOM.getSlotName(currentNode)];

          if (found) {
            found.addNode(view, currentNode, projectionSource, index);
            nodes.splice(i, 1);
            ii--; i--;
          }
        }
      } else {
        nodes.splice(i, 1);
        ii--; i--;
      }
    }

    for (let slotName in slots) {
      let slot = slots[slotName];

      if (slot.needsFallbackRendering) {
        slot.renderFallbackContent(view, nodes, projectionSource, index);
      }
    }
  }
}
<commit_msg>refactor(Slot): delay element injection<commit_after>import {inject} from 'aurelia-dependency-injection';
import {DOM} from 'aurelia-pal';
import {_isAllWhitespace} from './util';

let noNodes = Object.freeze([]);

export class SlotCustomAttribute {
  static inject() {
    return [DOM.Element];
  }

  constructor(element) {
    this.element = element;
    this.element.auSlotAttribute = this;
  }

  valueChanged(newValue, oldValue) {
    //console.log('au-slot', newValue);
  }
}

export class PassThroughSlot {
  constructor(anchor, name, destinationName, fallbackFactory) {
    this.anchor = anchor;
    this.anchor.viewSlot = this;
    this.name = name;
    this.destinationName = destinationName;
    this.fallbackFactory = fallbackFactory;
    this.destinationSlot = null;
    this.projections = 0;
    this.contentView = null;

    let attr = new SlotCustomAttribute(this.anchor);
    attr.value = this.destinationName;
  }

  get needsFallbackRendering() {
    return this.fallbackFactory && this.projections === 0;
  }

  renderFallbackContent(view, nodes, projectionSource, index) {
    if (this.contentView === null) {
      this.contentView = this.fallbackFactory.create(this.ownerView.container);
      this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);

      let slots = Object.create(null);
      slots[this.destinationSlot.name] = this.destinationSlot;

      ShadowDOM.distributeView(this.contentView, slots, projectionSource, index, this.destinationSlot.name);
    }
  }

  passThroughTo(destinationSlot) {
    this.destinationSlot = destinationSlot;
  }

  addNode(view, node, projectionSource, index) {
    if (this.contentView !== null) {
      this.contentView.removeNodes();
      this.contentView.detached();
      this.contentView.unbind();
      this.contentView = null;
    }

    if (node.viewSlot instanceof PassThroughSlot) {
      node.viewSlot.passThroughTo(this);
      return;
    }

    this.projections++;
    this.destinationSlot.addNode(view, node, projectionSource, index);
  }

  removeView(view, projectionSource) {
    this.projections--;
    this.destinationSlot.removeView(view, projectionSource);

    if (this.needsFallbackRendering) {
      this.renderFallbackContent(null, noNodes, projectionSource);
    }
  }

  removeAll(projectionSource) {
    this.projections = 0;
    this.destinationSlot.removeAll(projectionSource);

    if (this.needsFallbackRendering) {
      this.renderFallbackContent(null, noNodes, projectionSource);
    }
  }

  projectFrom(view, projectionSource) {
    this.destinationSlot.projectFrom(view, projectionSource);
  }

  created(ownerView) {
    this.ownerView = ownerView;
  }

  bind(view) {
    if (this.contentView) {
      this.contentView.bind(view.bindingContext, view.overrideContext);
    }
  }

  attached() {
    if (this.contentView) {
      this.contentView.attached();
    }
  }

  detached() {
    if (this.contentView) {
      this.contentView.detached();
    }
  }

  unbind() {
    if (this.contentView) {
      this.contentView.unbind();
    }
  }
}

export class ShadowSlot {
  constructor(anchor, name, fallbackFactory) {
    this.anchor = anchor;
    this.anchor.isContentProjectionSource = true;
    this.anchor.viewSlot = this;
    this.name = name;
    this.fallbackFactory = fallbackFactory;
    this.contentView = null;
    this.projections = 0;
    this.children = [];
    this.projectFromAnchors = null;
    this.destinationSlots = null;
  }

  get needsFallbackRendering() {
    return this.fallbackFactory && this.projections === 0;
  }

  addNode(view, node, projectionSource, index, destination) {
    if (this.contentView !== null) {
      this.contentView.removeNodes();
      this.contentView.detached();
      this.contentView.unbind();
      this.contentView = null;
    }

    if (node.viewSlot instanceof PassThroughSlot) {
      node.viewSlot.passThroughTo(this);
      return;
    }

    if (this.destinationSlots !== null) {
      ShadowDOM.distributeNodes(view, [node], this.destinationSlots, this, index);
    } else {
      node.auOwnerView = view;
      node.auProjectionSource = projectionSource;
      node.auAssignedSlot = this;

      let anchor = this._findAnchor(view, node, projectionSource, index);
      let parent = anchor.parentNode;

      parent.insertBefore(node, anchor);
      this.children.push(node);
      this.projections++;
    }
  }

  removeView(view, projectionSource) {
    if (this.destinationSlots !== null) {
      ShadowDOM.undistributeView(view, this.destinationSlots, this);
    } else if (this.contentView && this.contentView.hasSlots) {
      ShadowDOM.undistributeView(view, this.contentView.slots, projectionSource);
    } else {
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
      if (found) {
        let children = found.auProjectionChildren;

        for (let i = 0, ii = children.length; i < ii; ++i) {
          let child = children[i];

          if (child.auOwnerView === view) {
            children.splice(i, 1);
            view.fragment.appendChild(child);
            i--; ii--;
            this.projections--;
          }
        }

        if (this.needsFallbackRendering) {
          this.renderFallbackContent(view, noNodes, projectionSource);
        }
      }
    }
  }

  removeAll(projectionSource) {
    if (this.destinationSlots !== null) {
      ShadowDOM.undistributeAll(this.destinationSlots, this);
    } else if (this.contentView && this.contentView.hasSlots) {
      ShadowDOM.undistributeAll(this.contentView.slots, projectionSource);
    } else {
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);

      if (found) {
        let children = found.auProjectionChildren;
        for (let i = 0, ii = children.length; i < ii; ++i) {
          let child = children[i];
          child.auOwnerView.fragment.appendChild(child);
          this.projections--;
        }

        found.auProjectionChildren = [];

        if (this.needsFallbackRendering) {
          this.renderFallbackContent(null, noNodes, projectionSource);
        }
      }
    }
  }

  _findAnchor(view, node, projectionSource, index) {
    if (projectionSource) {
      //find the anchor associated with the projected view slot
      let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
      if (found) {
        if (index !== undefined) {
          let children = found.auProjectionChildren;
          let viewIndex = -1;
          let lastView;

          for (let i = 0, ii = children.length; i < ii; ++i) {
            let current = children[i];

            if (current.auOwnerView !== lastView) {
              viewIndex++;
              lastView = current.auOwnerView;

              if (viewIndex >= index && lastView !== view) {
                children.splice(i, 0, node);
                return current;
              }
            }
          }
        }

        found.auProjectionChildren.push(node);
        return found;
      }
    }

    return this.anchor;
  }

  projectTo(slots) {
    this.destinationSlots = slots;
  }

  projectFrom(view, projectionSource) {
    let anchor = DOM.createComment('anchor');
    let parent = this.anchor.parentNode;
    anchor.auSlotProjectFrom = projectionSource;
    anchor.auOwnerView = view;
    anchor.auProjectionChildren = [];
    parent.insertBefore(anchor, this.anchor);
    this.children.push(anchor);

    if (this.projectFromAnchors === null) {
      this.projectFromAnchors = [];
    }

    this.projectFromAnchors.push(anchor);
  }

  renderFallbackContent(view, nodes, projectionSource, index) {
    if (this.contentView === null) {
      this.contentView = this.fallbackFactory.create(this.ownerView.container);
      this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);
      this.contentView.insertNodesBefore(this.anchor);
    }

    if (this.contentView.hasSlots) {
      let slots = this.contentView.slots;
      let projectFromAnchors = this.projectFromAnchors;

      if (projectFromAnchors !== null) {
        for (let slotName in slots) {
          let slot = slots[slotName];

          for (let i = 0, ii = projectFromAnchors.length; i < ii; ++i) {
            let anchor = projectFromAnchors[i];
            slot.projectFrom(anchor.auOwnerView, anchor.auSlotProjectFrom);
          }
        }
      }

      this.fallbackSlots = slots;
      ShadowDOM.distributeNodes(view, nodes, slots, projectionSource, index);
    }
  }

  created(ownerView) {
    this.ownerView = ownerView;
  }

  bind(view) {
    if (this.contentView) {
      this.contentView.bind(view.bindingContext, view.overrideContext);
    }
  }

  attached() {
    if (this.contentView) {
      this.contentView.attached();
    }
  }

  detached() {
    if (this.contentView) {
      this.contentView.detached();
    }
  }

  unbind() {
    if (this.contentView) {
      this.contentView.unbind();
    }
  }
}

export class ShadowDOM {
  static defaultSlotKey = '__au-default-slot-key__';

  static getSlotName(node) {
    if (node.auSlotAttribute === undefined) {
      return ShadowDOM.defaultSlotKey;
    }

    return node.auSlotAttribute.value;
  }

  static distributeView(view, slots, projectionSource, index, destinationOverride) {
    let nodes;

    if (view === null) {
      nodes = noNodes;
    } else {
      let childNodes = view.fragment.childNodes;
      let ii = childNodes.length;
      nodes = new Array(ii);

      for (let i = 0; i < ii; ++i) {
        nodes[i] = childNodes[i];
      }
    }

    ShadowDOM.distributeNodes(
      view,
      nodes,
      slots,
      projectionSource,
      index,
      destinationOverride
    );
  }

  static undistributeView(view, slots, projectionSource) {
    for (let slotName in slots) {
      slots[slotName].removeView(view, projectionSource);
    }
  }

  static undistributeAll(slots, projectionSource) {
    for (let slotName in slots) {
      slots[slotName].removeAll(projectionSource);
    }
  }

  static distributeNodes(view, nodes, slots, projectionSource, index, destinationOverride) {
    for (let i = 0, ii = nodes.length; i < ii; ++i) {
      let currentNode = nodes[i];
      let nodeType = currentNode.nodeType;

      if (currentNode.isContentProjectionSource) {
        currentNode.viewSlot.projectTo(slots);

        for (let slotName in slots) {
          slots[slotName].projectFrom(view, currentNode.viewSlot);
        }

        nodes.splice(i, 1);
        ii--; i--;
      } else if (nodeType === 1 || nodeType === 3 || currentNode.viewSlot instanceof PassThroughSlot) { //project only elements and text
        if (nodeType === 3 && _isAllWhitespace(currentNode)) {
          nodes.splice(i, 1);
          ii--; i--;
        } else {
          let found = slots[destinationOverride || ShadowDOM.getSlotName(currentNode)];

          if (found) {
            found.addNode(view, currentNode, projectionSource, index);
            nodes.splice(i, 1);
            ii--; i--;
          }
        }
      } else {
        nodes.splice(i, 1);
        ii--; i--;
      }
    }

    for (let slotName in slots) {
      let slot = slots[slotName];

      if (slot.needsFallbackRendering) {
        slot.renderFallbackContent(view, nodes, projectionSource, index);
      }
    }
  }
}
<|endoftext|>


<commit_before>/* eslint-disable prefer-template */
/*!
 * Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
 */

import {waitForValue, SparkPlugin} from '@ciscospark/spark-core';

import reportRequest from './report-request';

const Ediscovery = SparkPlugin.extend({
  namespace: 'Ediscovery',

  @waitForValue('@')
  createReport(emails, keywords, spaceNames, spaceIds, range) {
    if ((typeof emails === 'undefined' || emails === null)
        || (typeof keywords === 'undefined' || keywords === null)
        || (typeof spaceNames === 'undefined' || spaceNames === null)
        || (typeof spaceIds === 'undefined' || spaceIds === null)
        || (typeof range === 'undefined' || range === null)) {
      throw new Error('Invalid parameter(s)');
    }

    const self = this;
    return this.asUUIDs(emails).then((uuids) => {
      const body = reportRequest;
      body.userIds = uuids;
      body.keywords = keywords;
      body.spaceNames = spaceNames;
      body.spaceIds = spaceIds;
      body.range = range;

      return self.request({
        method: 'POST',
        service: 'ediscovery',
        resource: 'reports',
        body
      }).then((res) => {
        console.log(res);
        return res;
      }).catch((reason) => {
        console.log(reason);
        return reason;
      });
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  /**
   * Retrieve the user UUID associated with each supplied email. If an email with no user
   * is found an error is thrown. If multiple such emails exist only the first encountered
   * throws an error.
   *
   * @param {Array.<String>} emails A list of emails to resolve
   * @returns {Promise} The UUIDs associated with the emails
   */
  asUUIDs(emails) {
    if (typeof emails === 'undefined' || emails === null) {
      throw new Error('Invalid parameter');
    }
    if (emails.length <= 0) {
      return Promise.resolve([]);
    }
    const promises = [];
    emails.forEach((userEmail) => {
      promises.push(
        // The people list API only supports a single email
        this.spark.people.list({email: userEmail})
          .then((result) => {
            if (result.items.length <= 0) {
              throw new Error('Unable to find user with email ' + userEmail);
            }
            const decodedId = Buffer.from(result.items[0].id, 'base64').toString();
            const uuid = decodedId.substring(decodedId.lastIndexOf('/') + 1, decodedId.length);
            return uuid;
          })
      );
    });
    return Promise.all(promises);
  },

  @waitForValue('@')
  getReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'GET',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  getReports() {
    return this.request({
      method: 'GET',
      service: 'ediscovery',
      resource: 'reports'
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  deleteReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'DELETE',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  restartReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'PUT',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  }

});

export default Ediscovery;
<commit_msg>docs(ediscovery): additional comments<commit_after>/* eslint-disable prefer-template */
/*!
 * Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
 */

import {waitForValue, SparkPlugin} from '@ciscospark/spark-core';

import reportRequest from './report-request';

const Ediscovery = SparkPlugin.extend({
  namespace: 'Ediscovery',

  @waitForValue('@')
  createReport(emails, keywords, spaceNames, spaceIds, range) {
    if ((typeof emails === 'undefined' || emails === null)
        || (typeof keywords === 'undefined' || keywords === null)
        || (typeof spaceNames === 'undefined' || spaceNames === null)
        || (typeof spaceIds === 'undefined' || spaceIds === null)
        || (typeof range === 'undefined' || range === null)) {
      throw new Error('Invalid parameter(s)');
    }

    const self = this;
    return this.asUUIDs(emails).then((uuids) => {
      const body = reportRequest;
      body.userIds = uuids;
      body.keywords = keywords;
      body.spaceNames = spaceNames;
      body.spaceIds = spaceIds;
      body.range = range;

      return self.request({
        method: 'POST',
        service: 'ediscovery',
        resource: 'reports',
        body
      }).then((res) => {
        console.log(res);
        return res;
      }).catch((reason) => {
        console.log(reason);
        return reason;
      });
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  /**
   * Retrieve the user UUID associated with each supplied email. If an email with no user
   * is found an error is thrown. If multiple such emails exist only the first encountered
   * throws an error.
   *
   * @param {Array.<String>} emails A list of emails to resolve
   * @returns {Promise} The UUIDs associated with the emails
   */
  asUUIDs(emails) {
    if (typeof emails === 'undefined' || emails === null) {
      throw new Error('Invalid parameter');
    }
    if (emails.length <= 0) {
      return Promise.resolve([]);
    }
    const promises = [];
    emails.forEach((userEmail) => {
      promises.push(
        // The people list API only supports a single email
        this.spark.people.list({email: userEmail})
          .then((result) => {
            if (result.items.length <= 0) {
              throw new Error('Unable to find user with email ' + userEmail);
            }
            // User id is base64 encoded and of the format Y2lzY29zcGFyazovL3VzL1BFT1BMRS81ZDU5Yjc5NS02ZmEyLTQ2NTQtOGVjMi03NjlkYjE1YzBkOWU
            const decodedId = Buffer.from(result.items[0].id, 'base64').toString();
            // Decode and strip out the uuid ciscospark://us/PEOPLE/5d59b795-6fa2-4654-8ec2-769db15c0d9e
            const uuid = decodedId.substring(decodedId.lastIndexOf('/') + 1, decodedId.length);
            return uuid;
          })
      );
    });
    return Promise.all(promises);
  },

  @waitForValue('@')
  getReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'GET',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  getReports() {
    return this.request({
      method: 'GET',
      service: 'ediscovery',
      resource: 'reports'
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  deleteReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'DELETE',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  },

  @waitForValue('@')
  restartReport(reportId) {
    if (typeof reportId === 'undefined' || reportId === null) {
      throw new Error('Invalid parameter(s)');
    }

    const id = reportId;
    return this.request({
      method: 'PUT',
      service: 'ediscovery',
      resource: 'reports/' + id
    }).then((res) => {
      console.log(res);
      return res;
    }).catch((reason) => {
      console.log(reason);
      return reason;
    });
  }

});

export default Ediscovery;
<|endoftext|>


<commit_before>export const Config = {
  Name: 'The Nokia Learning Store',
  // Source: '/',
  Source: '/LearningStore/',
  Mapping: ['Audience', 'Description', 'Objectives', 'Duration', 'Prerequisites', 'Testimonials', 'Associates', 'More information'],
  defaultIcon: 'img/seeMore.png',
  trackingID: 'UA-107717760-1', // Google Analytics
  // gun: 'https://nls-orvpzmwtij.now.sh/gun'
  gun: 'https://nokiaedu-gun.herokuapp.com/gun'
};<commit_msg>Dimmer icon fixed<commit_after>export const Config = {
  Name: 'The Nokia Learning Store',
  Source: '/',
  // Source: '/LearningStore/',
  Mapping: ['Audience', 'Description', 'Objectives', 'Duration', 'Prerequisites', 'Testimonials', 'Associates', 'More information'],
  defaultIcon: 'img/seeMore.png',
  trackingID: 'UA-107717760-1', // Google Analytics
  // gun: 'https://nls-orvpzmwtij.now.sh/gun'
  gun: 'https://nokiaedu-gun.herokuapp.com/gun'
};<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('schedulerApp', [
  'ngRoute',
  'ngResource'
])
.factory('db', [ '$resource', '$q', '$rootScope', '$location', function($resource, $q, $rootScope, $location) {

	var
		Things = $resource("http://"+$location.host()+":8000/rest/v1/things", {}),
		Rooms = $resource("http://"+$location.host()+":8000/rest/v1/rooms", {}),
		Tasks = $resource("http://"+$location.host()+":"+$location.port()+"/rest/v1/tasks", {}),
		Task = $resource("http://"+$location.host()+":"+$location.port()+"/rest/v1/tasks/:id", {}),
		refreshThings = function() {
			return Things.get({}).$promise.then(
				function(things) {
					service.things = {}
					angular.forEach(things.data,
						function(thing) {
							var found = false
							if (!thing.promoted || !thing.name || !thing.location) {
								// console.debug("skipping thing because not promoted, described or assigned to room", thing)
								return
							}
							angular.forEach(thing.device.channels, function(channel) {
								if (channel.supportedMethods && channel.supportedMethods.indexOf("turnOff") >= 0) {
									found = true
								}
							})
							if (found) {
								service.things[thing["id"]] = thing
							}
						}
					)
					return service
				}
			)
		},
		refreshRooms = function() {
			return Rooms.get({}).$promise.then(
				function(rooms) {
					service.rooms = {}
					angular.forEach(rooms.data, function(room) {
						service.rooms[room["id"]] = room
					})
					return service
				}
			)
		},
		refreshTasks = function() {
			return Tasks.get({}).$promise.then(
				function(tasks) {
					service.tasks = {}
					angular.forEach(tasks.schedule, function(task) {
						if (!task.tags || task.tags.indexOf("simple-ui") < 0) {
							return;
						}
						if (task.description && task.description != '') {
							service.tasks[task["id"]] = task
						}
					})
					return service
				}
			)
		},
		service = {
			things: { } ,
			rooms: { } ,
			tasks: { } ,
			save: function(task) {
				var deferred = $q.defer()
				Tasks.save(
					{},
					task,
					function(r) {
						refreshTasks().then(
							function() { deferred.resolve(r) },
							deferred.reject
						)},
					deferred.reject)
				return deferred.promise
			},
			delete: function(id) {
				var deferred = $q.defer()
				Task.delete({"id": id},
					function(r) {
						refreshTasks().then(function() { deferred.resolve(r)}, deferred.reject)
					},
					deferred.reject
				)
				return deferred.promise
			},
			refresh: function() {
				return $q.all([ refreshRooms(),	refreshThings(), refreshTasks() ]).then(
					function() {
						return service
					}
				)
			}
		}
	return service
}])
.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/list', {templateUrl: 'task-list.html', controller: 'TaskList'});
  $routeProvider.when('/edit/:id', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.when('/create', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.otherwise({redirectTo: '/list'});
}])
.controller('ModelRefresh', ['$scope', 'db', function($scope, db) {
	db.refresh().then(
		function(things) {
			return things
		},
		function(m) {
			if (m && m.data) {
				$scope.message = m.data
			} else {
				$scope.message = "An error occurred."
			}
			console.debug("an error occurred while refreshing the model: ", m)
		}
	)
}])
.controller('TaskEdit', ['$scope', '$location', 'db', '$routeParams', function($scope, $location, db, $routeParams) {

	$scope.actionModels = {};
	$scope.isDescriptionFrozen = false
	$scope.repeatDaily = true

	$scope.thingToModel = function(thing) {
		var result = {}
		result.id = thing.id
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			return null
		}
		result.room = room.name
		result.on = "true"
		return result
	}

	$scope.formatTime = function (date) {
	    var h = date.getHours();
	    var m = date.getMinutes();
	    var s = date.getSeconds();
	    var pad = function(d) { return d <= 9 ? '0'+d : d }
	    return ''+pad(h)+":"+pad(m)+":"+pad(s)
	}

	$scope.formatDate = function (date) {
	    var y = date.getFullYear();
	    var m = date.getMonth()+1;
	    var d = date.getDate();
	    var pad = function(d) { return d <= 9 ? '0'+d : d }
	    return ''+y+"-"+pad(m)+"-"+pad(d)
	}

	$scope.actionToModel = function(action) {
	    // {
        //    "action" : "turnOn",
        //    "thingID" : "94dc7d1a-aa67-11e4-803a-7c669d02a706",
        //     "type" : "thing-action"
        // }
        //
        // ==>
        //
	    // {
	    //	  "id": thing-id
        //    "description" : "thing description",
        //	  "room": "room description"
        //	  "on": true
        // }
        //

		var result = {}
		switch (action["action"]) {
		case "turnOn":
			result.on = "true"
			break
		case "turnOff":
			result.on = "false"
			break
		default:
			console.debug("bad action ", action)
			return null
		}

		if (action.type != "thing-action") {
			console.debug("bad type ", action.type)
			return null
		}

		if (!action.thingID) {
			console.debug("missing thing id")
			return null
		}

		result.id = action.thingID
		var thing = db.things[result.id]
		if (!thing) {
			console.debug("invalid thing id", result.id)
			return null
		}
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			console.debug("invalid room id", thing.location)
			return null
		}
		result.room = room.name
		result.selected = true

		return result
	}

	$scope.task = function() {
		return db.tasks[$routeParams["id"]]
	}

	$scope.save = function() {
		$scope.message = ""
		var rule, param

		switch ($scope.timeOfDay) {
		case "dawn":
		case "dusk":
		case "sunrise":
		case "sunset":
			rule = $scope.timeOfDay
			param = ""
			break
		default:
			var
				now = new Date(),
				ts = new Date($scope.formatDate(now)+" "+$scope.timeOfDay)

			if (!ts.getFullYear()) {
				$scope.message = "enter a time of the form hh:mm:dd"
			} else {
				if (ts < now) {
					ts.setDate(ts.getDate()+1)
				}
				if ($scope.repeatDaily) {
					rule = "time-of-day"
					param = $scope.formatTime(ts)
				} else {
					rule = "timestamp"
					param = $scope.formatDate(ts) + " " + $scope.formatTime(ts)
				}
			}
			break
		}

		var desc = (($scope.description == '') ? '@ '+$scope.timeOfDay : $scope.description )

		var open = (function() {
			var results = []
			angular.forEach($scope.actionModels, function(m) {
				if (m.selected) {
					results.push(
						{
							"type": "thing-action",
							"action": (m.on == "true" ? "turnOn" : "turnOff"),
							"thingID": m.id
						}
					)
				}
			})
			return results
		}())

		var task = {
			"id": $routeParams["id"],
			"description": desc,
			"tags": ["simple-ui"],
			"open": open,
			"close": [],
			"window": {
				"after": {
					"rule": rule,
					"param": param
				},
				"before": {
					"rule": "delay",
					"param": "00:01:00"
				}
			}
		}

		db.save(task).then(
			function() {
				$location.path('/list')
			}, function(m) {
				if (m && m.data) {
					$scope.message = m.data
				} else {
					$scope.message = "An error occurred."
				}
				console.debug(m)
			})
	}

	$scope.delete = function() {
		db.delete($routeParams["id"]).then(
			function() {
				$location.path('/list')
			}, function(m) {
				if (m && m.data) {
					$scope.message = m.data
				} else {
					$scope.message = "An error occurred."
				}
				console.debug(m)
			})
	}

	$scope.cancel = function() {
		$location.path('/list')
	}

	$scope.freezeDescription = function() {
		$scope.isDescriptionFrozen = true
	}

	$scope.toggleSelect = function(model) {
		model.selected = !model.selected
	}

	$scope.toggleActionState = function(model) {
		model.on = ! model.on
	}

	$scope.setRepeatDaily = function(value) {
		$scope.repeatDaily = value;
	}

	$scope.$watch('task()', function(task) {
		angular.forEach(db.things, function(t) {
			var m = $scope.thingToModel(t)
			if (m) {
				$scope.actionModels[t["id"]] = m
			}
		})

		$scope.timeOfDay = $scope.formatTime(new Date(new Date().valueOf()+(60*1000)))
		$scope.description = '@ '+$scope.timeOfDay
		$scope.repeatDaily = true

		if (!task) {
			return
		}

		$scope.description = task.description

		angular.forEach(task.open, function(action) {
			var model = $scope.actionToModel(action)
			if (model && $scope.actionModels[model.id]) {
				$scope.actionModels[model.id] = model
			} else {
				console.debug("found an action for a thing that no longer exists: ", action)
			}
		})

		switch (task.window.after.rule) {
		case "sunrise":
		case "sunset":
		case "dawn":
		case "dusk":
			$scope.timeOfDay = task.window.after.rule
			break;
		case "time-of-day":
			$scope.timeOfDay = task.window.after.param
			break;
		case "timestamp":
			var ts = new Date(task.window.after.param)
			if (ts.getFullYear()) {
				$scope.timeOfDay = $scope.formatTime(ts)
				$scope.repeatDaily = false
			}
		default:
			console.debug("can't edit rule of type: ", task.window.after.rule)
			return
		}

	})

	$scope.$watch('timeOfDay', function() {
		if (!$scope.isDescriptionFrozen) {
			$scope.description = '@ '+$scope.timeOfDay
		}
	});

}])
.controller('TaskList', ['$scope', 'db', '$rootScope', function($scope, db, $rootScope) {
	$scope.tasks = {}
	$scope.db = db
	$scope.$watch("db.tasks", function(tasks) {
		$scope.tasks = db.tasks
	})
}])

<commit_msg>Return if the timestamp is invalid.<commit_after>'use strict';

// Declare app level module which depends on views, and components
angular.module('schedulerApp', [
  'ngRoute',
  'ngResource'
])
.factory('db', [ '$resource', '$q', '$rootScope', '$location', function($resource, $q, $rootScope, $location) {

	var
		Things = $resource("http://"+$location.host()+":8000/rest/v1/things", {}),
		Rooms = $resource("http://"+$location.host()+":8000/rest/v1/rooms", {}),
		Tasks = $resource("http://"+$location.host()+":"+$location.port()+"/rest/v1/tasks", {}),
		Task = $resource("http://"+$location.host()+":"+$location.port()+"/rest/v1/tasks/:id", {}),
		refreshThings = function() {
			return Things.get({}).$promise.then(
				function(things) {
					service.things = {}
					angular.forEach(things.data,
						function(thing) {
							var found = false
							if (!thing.promoted || !thing.name || !thing.location) {
								// console.debug("skipping thing because not promoted, described or assigned to room", thing)
								return
							}
							angular.forEach(thing.device.channels, function(channel) {
								if (channel.supportedMethods && channel.supportedMethods.indexOf("turnOff") >= 0) {
									found = true
								}
							})
							if (found) {
								service.things[thing["id"]] = thing
							}
						}
					)
					return service
				}
			)
		},
		refreshRooms = function() {
			return Rooms.get({}).$promise.then(
				function(rooms) {
					service.rooms = {}
					angular.forEach(rooms.data, function(room) {
						service.rooms[room["id"]] = room
					})
					return service
				}
			)
		},
		refreshTasks = function() {
			return Tasks.get({}).$promise.then(
				function(tasks) {
					service.tasks = {}
					angular.forEach(tasks.schedule, function(task) {
						if (!task.tags || task.tags.indexOf("simple-ui") < 0) {
							return;
						}
						if (task.description && task.description != '') {
							service.tasks[task["id"]] = task
						}
					})
					return service
				}
			)
		},
		service = {
			things: { } ,
			rooms: { } ,
			tasks: { } ,
			save: function(task) {
				var deferred = $q.defer()
				Tasks.save(
					{},
					task,
					function(r) {
						refreshTasks().then(
							function() { deferred.resolve(r) },
							deferred.reject
						)},
					deferred.reject)
				return deferred.promise
			},
			delete: function(id) {
				var deferred = $q.defer()
				Task.delete({"id": id},
					function(r) {
						refreshTasks().then(function() { deferred.resolve(r)}, deferred.reject)
					},
					deferred.reject
				)
				return deferred.promise
			},
			refresh: function() {
				return $q.all([ refreshRooms(),	refreshThings(), refreshTasks() ]).then(
					function() {
						return service
					}
				)
			}
		}
	return service
}])
.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/list', {templateUrl: 'task-list.html', controller: 'TaskList'});
  $routeProvider.when('/edit/:id', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.when('/create', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.otherwise({redirectTo: '/list'});
}])
.controller('ModelRefresh', ['$scope', 'db', function($scope, db) {
	db.refresh().then(
		function(things) {
			return things
		},
		function(m) {
			if (m && m.data) {
				$scope.message = m.data
			} else {
				$scope.message = "An error occurred."
			}
			console.debug("an error occurred while refreshing the model: ", m)
		}
	)
}])
.controller('TaskEdit', ['$scope', '$location', 'db', '$routeParams', function($scope, $location, db, $routeParams) {

	$scope.actionModels = {};
	$scope.isDescriptionFrozen = false
	$scope.repeatDaily = true

	$scope.thingToModel = function(thing) {
		var result = {}
		result.id = thing.id
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			return null
		}
		result.room = room.name
		result.on = "true"
		return result
	}

	$scope.formatTime = function (date) {
	    var h = date.getHours();
	    var m = date.getMinutes();
	    var s = date.getSeconds();
	    var pad = function(d) { return d <= 9 ? '0'+d : d }
	    return ''+pad(h)+":"+pad(m)+":"+pad(s)
	}

	$scope.formatDate = function (date) {
	    var y = date.getFullYear();
	    var m = date.getMonth()+1;
	    var d = date.getDate();
	    var pad = function(d) { return d <= 9 ? '0'+d : d }
	    return ''+y+"-"+pad(m)+"-"+pad(d)
	}

	$scope.actionToModel = function(action) {
	    // {
        //    "action" : "turnOn",
        //    "thingID" : "94dc7d1a-aa67-11e4-803a-7c669d02a706",
        //     "type" : "thing-action"
        // }
        //
        // ==>
        //
	    // {
	    //	  "id": thing-id
        //    "description" : "thing description",
        //	  "room": "room description"
        //	  "on": true
        // }
        //

		var result = {}
		switch (action["action"]) {
		case "turnOn":
			result.on = "true"
			break
		case "turnOff":
			result.on = "false"
			break
		default:
			console.debug("bad action ", action)
			return null
		}

		if (action.type != "thing-action") {
			console.debug("bad type ", action.type)
			return null
		}

		if (!action.thingID) {
			console.debug("missing thing id")
			return null
		}

		result.id = action.thingID
		var thing = db.things[result.id]
		if (!thing) {
			console.debug("invalid thing id", result.id)
			return null
		}
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			console.debug("invalid room id", thing.location)
			return null
		}
		result.room = room.name
		result.selected = true

		return result
	}

	$scope.task = function() {
		return db.tasks[$routeParams["id"]]
	}

	$scope.save = function() {
		$scope.message = ""
		var rule, param

		switch ($scope.timeOfDay) {
		case "dawn":
		case "dusk":
		case "sunrise":
		case "sunset":
			rule = $scope.timeOfDay
			param = ""
			break
		default:
			var
				now = new Date(),
				ts = new Date($scope.formatDate(now)+" "+$scope.timeOfDay)

			if (!ts.getFullYear()) {
				$scope.message = "enter a time of the form hh:mm:dd"
				return
			} else {
				if (ts < now) {
					ts.setDate(ts.getDate()+1)
				}
				if ($scope.repeatDaily) {
					rule = "time-of-day"
					param = $scope.formatTime(ts)
				} else {
					rule = "timestamp"
					param = $scope.formatDate(ts) + " " + $scope.formatTime(ts)
				}
			}
			break
		}

		var desc = (($scope.description == '') ? '@ '+$scope.timeOfDay : $scope.description )

		var open = (function() {
			var results = []
			angular.forEach($scope.actionModels, function(m) {
				if (m.selected) {
					results.push(
						{
							"type": "thing-action",
							"action": (m.on == "true" ? "turnOn" : "turnOff"),
							"thingID": m.id
						}
					)
				}
			})
			return results
		}())

		var task = {
			"id": $routeParams["id"],
			"description": desc,
			"tags": ["simple-ui"],
			"open": open,
			"close": [],
			"window": {
				"after": {
					"rule": rule,
					"param": param
				},
				"before": {
					"rule": "delay",
					"param": "00:01:00"
				}
			}
		}

		db.save(task).then(
			function() {
				$location.path('/list')
			}, function(m) {
				if (m && m.data) {
					$scope.message = m.data
				} else {
					$scope.message = "An error occurred."
				}
				console.debug(m)
			})
	}

	$scope.delete = function() {
		db.delete($routeParams["id"]).then(
			function() {
				$location.path('/list')
			}, function(m) {
				if (m && m.data) {
					$scope.message = m.data
				} else {
					$scope.message = "An error occurred."
				}
				console.debug(m)
			})
	}

	$scope.cancel = function() {
		$location.path('/list')
	}

	$scope.freezeDescription = function() {
		$scope.isDescriptionFrozen = true
	}

	$scope.toggleSelect = function(model) {
		model.selected = !model.selected
	}

	$scope.toggleActionState = function(model) {
		model.on = ! model.on
	}

	$scope.setRepeatDaily = function(value) {
		$scope.repeatDaily = value;
	}

	$scope.$watch('task()', function(task) {
		angular.forEach(db.things, function(t) {
			var m = $scope.thingToModel(t)
			if (m) {
				$scope.actionModels[t["id"]] = m
			}
		})

		$scope.timeOfDay = $scope.formatTime(new Date(new Date().valueOf()+(60*1000)))
		$scope.description = '@ '+$scope.timeOfDay
		$scope.repeatDaily = true

		if (!task) {
			return
		}

		$scope.description = task.description

		angular.forEach(task.open, function(action) {
			var model = $scope.actionToModel(action)
			if (model && $scope.actionModels[model.id]) {
				$scope.actionModels[model.id] = model
			} else {
				console.debug("found an action for a thing that no longer exists: ", action)
			}
		})

		switch (task.window.after.rule) {
		case "sunrise":
		case "sunset":
		case "dawn":
		case "dusk":
			$scope.timeOfDay = task.window.after.rule
			break;
		case "time-of-day":
			$scope.timeOfDay = task.window.after.param
			break;
		case "timestamp":
			var ts = new Date(task.window.after.param)
			if (ts.getFullYear()) {
				$scope.timeOfDay = $scope.formatTime(ts)
				$scope.repeatDaily = false
			}
		default:
			console.debug("can't edit rule of type: ", task.window.after.rule)
			return
		}

	})

	$scope.$watch('timeOfDay', function() {
		if (!$scope.isDescriptionFrozen) {
			$scope.description = '@ '+$scope.timeOfDay
		}
	});

}])
.controller('TaskList', ['$scope', 'db', '$rootScope', function($scope, db, $rootScope) {
	$scope.tasks = {}
	$scope.db = db
	$scope.$watch("db.tasks", function(tasks) {
		$scope.tasks = db.tasks
	})
}])

<|endoftext|>