<commit_before>/*
 * (c) Copyright Ascensio System SIA 2010-2016
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

const cluster = require('cluster');
const configCommon = require('config');
const config = configCommon.get('services.CoAuthoring');
//process.env.NODE_ENV = config.get('server.mode');

const logger = require('./../../Common/sources/logger');

if (cluster.isMaster) {
  const fs = require('fs');
  const co = require('co');

  //const numCPUs = require('os').cpus().length;
  const license = require('./../../Common/sources/license');

  //const cfgWorkerPerCpu = config.get('server.workerpercpu');
  var licenseInfo, workersCount = 0;
  const readLicense = function* () {
    licenseInfo = yield* license.readLicense();
    workersCount = Math.min(1, licenseInfo.count/*, Math.ceil(numCPUs * cfgWorkerPerCpu)*/);
  };
  const updateLicenseWorker = (worker) => {
    worker.send({data: licenseInfo});
  };
  const updateWorkers = () => {
    var i;
    const arrKeyWorkers = Object.keys(cluster.workers);
    if (arrKeyWorkers.length < workersCount) {
      for (i = arrKeyWorkers.length; i < workersCount; ++i) {
        const newWorker = cluster.fork();
        logger.warn('worker %s started.', newWorker.process.pid);
      }
    } else {
      for (i = workersCount; i < arrKeyWorkers.length; ++i) {
        const killWorker = cluster.workers[arrKeyWorkers[i]];
        if (killWorker) {
          killWorker.kill();
        }
      }
    }
  };
  const updateLicense = () => {
    return co(function*() {
      try {
        yield* readLicense();
        logger.warn('update cluster with %s workers', workersCount);
        for (var i in cluster.workers) {
          updateLicenseWorker(cluster.workers[i]);
        }
        updateWorkers();
      } catch (err) {
        logger.error('updateLicense error:\r\n%s', err.stack);
      }
    });
  };

  cluster.on('fork', (worker) => {
    updateLicenseWorker(worker);
  });
  cluster.on('exit', (worker) => {
    logger.warn('worker %s died.', worker.process.pid);
    updateWorkers();
  });

  updateLicense();

  fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
  setInterval(updateLicense, 86400000);
} else {
  const express = require('express');
  const http = require('http');
  const urlModule = require('url');
  const path = require('path');
  const bodyParser = require("body-parser");
  const mime = require('mime');
  const docsCoServer = require('./DocsCoServer');
  const canvasService = require('./canvasservice');
  const converterService = require('./converterservice');
  const fontService = require('./fontservice');
  const fileUploaderService = require('./fileuploaderservice');
  const constants = require('./../../Common/sources/constants');
  const utils = require('./../../Common/sources/utils');
  const configStorage = configCommon.get('storage');
  const app = express();
  var server = null;

  logger.warn('Express server starting...');

  server = http.createServer(app);

  if (config.has('server.static_content')) {
    var staticContent = config.get('server.static_content');
    for (var i = 0; i < staticContent.length; ++i) {
      var staticContentElem = staticContent[i];
      app.use(staticContentElem['name'], express.static(staticContentElem['path']));
    }
  }

  if (configStorage.has('fs.folderPath')) {
    var cfgBucketName = configStorage.get('bucketName');
    var cfgStorageFolderName = configStorage.get('storageFolderName');
    app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
      var index = req.url.lastIndexOf('/');
      if (-1 != index) {
        var contentDisposition = req.query['disposition'] || 'attachment';
        var sendFileOptions = {
          root: configStorage.get('fs.folderPath'),
          dotfiles: 'deny',
          headers: {
            'Content-Disposition': contentDisposition
          }
        };
        var urlParsed = urlModule.parse(req.url);
        if (urlParsed && urlParsed.pathname) {
          var filename = decodeURIComponent(path.basename(urlParsed.pathname));
          sendFileOptions.headers['Content-Type'] = mime.lookup(filename);
        }
        var realUrl = req.url.substring(0, index);
        res.sendFile(realUrl, sendFileOptions, (err) => {
          if (err) {
            logger.error(err);
            res.status(err.status).end();
          }
        });
      } else {
        req.sendStatus(404)
      }
    });
  }

  // Если захочется использовать 'development' и 'production',
  // то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
  // Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
  docsCoServer.install(server, () => {
    server.listen(config.get('server.port'), () => {
      logger.warn("Express server listening on port %d in %s mode", config.get('server.port'), app.settings.env);
    });

    app.get('/index.html', (req, res) => {
      res.send('Server is functioning normally. Version: ' + docsCoServer.version);
    });

    app.get('/coauthoring/CommandService.ashx', docsCoServer.commandFromServer);
    app.post('/coauthoring/CommandService.ashx', docsCoServer.commandFromServer);

    if (config.has('server.fonts_route')) {
      var fontsRoute = config.get('server.fonts_route');
      app.get('/' + fontsRoute + 'native/:fontname', fontService.getFont);
      app.get('/' + fontsRoute + 'js/:fontname', fontService.getFont);
      app.get('/' + fontsRoute + 'odttf/:fontname', fontService.getFont);
    }

    app.get('/ConvertService.ashx', converterService.convert);
    app.post('/ConvertService.ashx', converterService.convert);

    var rawFileParser = bodyParser.raw({ inflate: true, limit: config.get('server.limits_tempfile_upload'), type: '*/*' });
    app.get('/FileUploader.ashx', rawFileParser, fileUploaderService.uploadTempFile);
    app.post('/FileUploader.ashx', rawFileParser, fileUploaderService.uploadTempFile);

    var docIdRegExp = new RegExp("^[" + constants.DOC_ID_PATTERN + "]*$", 'i');
    app.param('docid', (req, res, next, val) => {
      if (docIdRegExp.test(val)) {
        next();
      } else {
        res.sendStatus(403);
      }
    });
    app.param('index', (req, res, next, val) => {
      if (!isNaN(parseInt(val))) {
        next();
      } else {
        res.sendStatus(403);
      }
    });
    app.post('/uploadold/:docid/:userid/:index/:vkey?', fileUploaderService.uploadImageFileOld);
    app.post('/upload/:docid/:userid/:index/:vkey?', rawFileParser, fileUploaderService.uploadImageFile);

    app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
    app.get('/healthcheck', converterService.convertHealthCheck);
  });

  process.on('message', (msg) => {
    if (!docsCoServer) {
      return;
    }
    docsCoServer.setLicenseInfo(msg.data);
  });
}

process.on('uncaughtException', (err) => {
  logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
  logger.error(err.stack);
  logger.shutdown(() => {
    process.exit(1);
  });
});<commit_msg>http DELETE works like GET on static content<commit_after>/*
 * (c) Copyright Ascensio System SIA 2010-2016
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

const cluster = require('cluster');
const configCommon = require('config');
const config = configCommon.get('services.CoAuthoring');
//process.env.NODE_ENV = config.get('server.mode');

const logger = require('./../../Common/sources/logger');

if (cluster.isMaster) {
  const fs = require('fs');
  const co = require('co');

  //const numCPUs = require('os').cpus().length;
  const license = require('./../../Common/sources/license');

  //const cfgWorkerPerCpu = config.get('server.workerpercpu');
  var licenseInfo, workersCount = 0;
  const readLicense = function* () {
    licenseInfo = yield* license.readLicense();
    workersCount = Math.min(1, licenseInfo.count/*, Math.ceil(numCPUs * cfgWorkerPerCpu)*/);
  };
  const updateLicenseWorker = (worker) => {
    worker.send({data: licenseInfo});
  };
  const updateWorkers = () => {
    var i;
    const arrKeyWorkers = Object.keys(cluster.workers);
    if (arrKeyWorkers.length < workersCount) {
      for (i = arrKeyWorkers.length; i < workersCount; ++i) {
        const newWorker = cluster.fork();
        logger.warn('worker %s started.', newWorker.process.pid);
      }
    } else {
      for (i = workersCount; i < arrKeyWorkers.length; ++i) {
        const killWorker = cluster.workers[arrKeyWorkers[i]];
        if (killWorker) {
          killWorker.kill();
        }
      }
    }
  };
  const updateLicense = () => {
    return co(function*() {
      try {
        yield* readLicense();
        logger.warn('update cluster with %s workers', workersCount);
        for (var i in cluster.workers) {
          updateLicenseWorker(cluster.workers[i]);
        }
        updateWorkers();
      } catch (err) {
        logger.error('updateLicense error:\r\n%s', err.stack);
      }
    });
  };

  cluster.on('fork', (worker) => {
    updateLicenseWorker(worker);
  });
  cluster.on('exit', (worker) => {
    logger.warn('worker %s died.', worker.process.pid);
    updateWorkers();
  });

  updateLicense();

  fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
  setInterval(updateLicense, 86400000);
} else {
  const express = require('express');
  const http = require('http');
  const urlModule = require('url');
  const path = require('path');
  const bodyParser = require("body-parser");
  const mime = require('mime');
  const docsCoServer = require('./DocsCoServer');
  const canvasService = require('./canvasservice');
  const converterService = require('./converterservice');
  const fontService = require('./fontservice');
  const fileUploaderService = require('./fileuploaderservice');
  const constants = require('./../../Common/sources/constants');
  const utils = require('./../../Common/sources/utils');
  const configStorage = configCommon.get('storage');
  const app = express();
  var server = null;

  logger.warn('Express server starting...');

  server = http.createServer(app);

  if (config.has('server.static_content')) {
    var staticContent = config.get('server.static_content');
    for (var i = 0; i < staticContent.length; ++i) {
      var staticContentElem = staticContent[i];
      app.use(staticContentElem['name'], express.static(staticContentElem['path']));
    }
  }

  if (configStorage.has('fs.folderPath')) {
    var cfgBucketName = configStorage.get('bucketName');
    var cfgStorageFolderName = configStorage.get('storageFolderName');
    app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
      var index = req.url.lastIndexOf('/');
      if ('GET' === req.method && -1 != index) {
        var contentDisposition = req.query['disposition'] || 'attachment';
        var sendFileOptions = {
          root: configStorage.get('fs.folderPath'),
          dotfiles: 'deny',
          headers: {
            'Content-Disposition': contentDisposition
          }
        };
        var urlParsed = urlModule.parse(req.url);
        if (urlParsed && urlParsed.pathname) {
          var filename = decodeURIComponent(path.basename(urlParsed.pathname));
          sendFileOptions.headers['Content-Type'] = mime.lookup(filename);
        }
        var realUrl = req.url.substring(0, index);
        res.sendFile(realUrl, sendFileOptions, (err) => {
          if (err) {
            logger.error(err);
            res.status(err.status).end();
          }
        });
      } else {
        res.sendStatus(404)
      }
    });
  }

  // Если захочется использовать 'development' и 'production',
  // то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
  // Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
  docsCoServer.install(server, () => {
    server.listen(config.get('server.port'), () => {
      logger.warn("Express server listening on port %d in %s mode", config.get('server.port'), app.settings.env);
    });

    app.get('/index.html', (req, res) => {
      res.send('Server is functioning normally. Version: ' + docsCoServer.version);
    });

    app.get('/coauthoring/CommandService.ashx', docsCoServer.commandFromServer);
    app.post('/coauthoring/CommandService.ashx', docsCoServer.commandFromServer);

    if (config.has('server.fonts_route')) {
      var fontsRoute = config.get('server.fonts_route');
      app.get('/' + fontsRoute + 'native/:fontname', fontService.getFont);
      app.get('/' + fontsRoute + 'js/:fontname', fontService.getFont);
      app.get('/' + fontsRoute + 'odttf/:fontname', fontService.getFont);
    }

    app.get('/ConvertService.ashx', converterService.convert);
    app.post('/ConvertService.ashx', converterService.convert);

    var rawFileParser = bodyParser.raw({ inflate: true, limit: config.get('server.limits_tempfile_upload'), type: '*/*' });
    app.get('/FileUploader.ashx', rawFileParser, fileUploaderService.uploadTempFile);
    app.post('/FileUploader.ashx', rawFileParser, fileUploaderService.uploadTempFile);

    var docIdRegExp = new RegExp("^[" + constants.DOC_ID_PATTERN + "]*$", 'i');
    app.param('docid', (req, res, next, val) => {
      if (docIdRegExp.test(val)) {
        next();
      } else {
        res.sendStatus(403);
      }
    });
    app.param('index', (req, res, next, val) => {
      if (!isNaN(parseInt(val))) {
        next();
      } else {
        res.sendStatus(403);
      }
    });
    app.post('/uploadold/:docid/:userid/:index/:vkey?', fileUploaderService.uploadImageFileOld);
    app.post('/upload/:docid/:userid/:index/:vkey?', rawFileParser, fileUploaderService.uploadImageFile);

    app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
    app.get('/healthcheck', converterService.convertHealthCheck);
  });

  process.on('message', (msg) => {
    if (!docsCoServer) {
      return;
    }
    docsCoServer.setLicenseInfo(msg.data);
  });
}

process.on('uncaughtException', (err) => {
  logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
  logger.error(err.stack);
  logger.shutdown(() => {
    process.exit(1);
  });
});<|endoftext|>


<commit_before>/**
 * Npm module for Unicode CLDR JSON data
 *
 * Copyright 2013 Rafael Xavier de Souza
 * Released under the MIT license
 * https://github.com/rxaviers/cldr-data-npm/blob/master/LICENSE-MIT
 */

"use strict";

var cldrDownloader = require("cldr-data-downloader");
var path = require("path");
var urls = require("./urls");

var url = urls[process.env.CLDR_COVERAGE || "core"];

if (process.env.CLDR_URL) {
  url = url.replace(
    "http://www.unicode.org/Public/cldr",
    process.env.CLDR_URL.replace(/\/$/, "")
  );
}

cldrDownloader(
  url,
  path.join(__dirname, "json"),
  function(error) {
    if (error) {
      console.error("Whops", error.message);
      exit(1);
    }
  }
);
<commit_msg>Define `exit = process.exit`<commit_after>/**
 * Npm module for Unicode CLDR JSON data
 *
 * Copyright 2013 Rafael Xavier de Souza
 * Released under the MIT license
 * https://github.com/rxaviers/cldr-data-npm/blob/master/LICENSE-MIT
 */

"use strict";

var cldrDownloader = require("cldr-data-downloader");
var exit = process.exit;
var path = require("path");
var urls = require("./urls");

var url = urls[process.env.CLDR_COVERAGE || "core"];

if (process.env.CLDR_URL) {
  url = url.replace(
    "http://www.unicode.org/Public/cldr",
    process.env.CLDR_URL.replace(/\/$/, "")
  );
}

cldrDownloader(
  url,
  path.join(__dirname, "json"),
  function(error) {
    if (error) {
      console.error("Whops", error.message);
      exit(1);
    }
  }
);
<|endoftext|>


<commit_before>'use strict';

(function(jQuery) {

  var $ = jQuery;

  var FOCUS_GENE_FAMILY = 'phytozome_10_2.59088092';
  var NEW_FOCUS_GENE_FAMILY = 'legfed_v1_0.L_JGH6XN';
  //var NEW_FOCUS_GENE_FAMILY = 'legfed_v1_0.L.FTX7K';
  var FOCUS_GENE = 'vigra.Vradi01g03360';
  var FOCUS_PROTEIN = FOCUS_GENE + '.1';
  var FOCUS_GENE_FUNCTION = 'gamma-glutamyl transpeptidase';
  var ALT_GENE = 'vigra.Vradi0091s00130';
  var ALT_PROTEIN = ALT_GENE + '.1';

  var SELECTOR = {
    welcome: '#site-name',
    searchBtn: "a:contains('Gene Search')",
    descriptors: 'th.views-field-description',
    formFieldDescr: '#edit-description',
    formFieldAbbrev: '#edit-abbreviation',
    submitBtn: '#edit-submit-gene',
    searchResult: 'th.views-field-name',
    functionalDesc: 'th.views-field-description',
    geneFamilyLink:'a[href*="'+FOCUS_GENE+'"]:contains("'+NEW_FOCUS_GENE_FAMILY+'")',
    phylotreeFocusProtein: '#phylogram g.legume:contains("'+ FOCUS_PROTEIN +'")',
    phylotreeAltProtein: '#phylogram g.legume:contains("'+ ALT_PROTEIN +'")',
    popup: '#node-dialog a:contains("Find similar")',
    contextViewerLink: "#node-dialog a[href*='lis_context_viewer']",
    contextFocusGene: 'path.point.focus:first',
    familyLegendButton: 'button:contains("Legend")',
    contextOrderControl: '#order',
    contextLocus: 'g.legend:has(:contains("'+NEW_FOCUS_GENE_FAMILY+'"))',
    contextFocus: 'h4:contains("'+NEW_FOCUS_GENE_FAMILY+'")',
    contextFamilyLink: 'a[href*="'+NEW_FOCUS_GENE_FAMILY+'"]',
    contact: 'a:contains("Contact")',
    msaButton:        '#msa-toggle',
    msaDialog:        '#msa-dialog',
    taxaButton:       '#taxa-toggle',
    taxaDialog:       '#taxa-dialog',
  };

  $.fn.d3Click = function () {
    this.each(function (i, e) {
      var evt = new MouseEvent('click');
      e.dispatchEvent(evt);
    });
  };

  var tour = new Tour({
    name: 'gene-to-phylotree-to-context-viewer',
    keyboard: true,
    //debug: true,
    orphan: true,
    template: lisTours.template.noPrevBtnTemplate,
    steps : [
      {
        title: 'Gene Tour: Welcome to LIS!',
        content: 'Let\'s go the legumeinfo.org homepage, where the Gene Tour will begin.  Use the Next button or → (right arrow key) to advance the tour.',
        placement: 'bottom',
        element: SELECTOR.welcome,
        reflex: true,
      }, {
        title: 'Gene Tour: Getting started',
        path: '/home',
        content: "This tour will provide an example of navigating LIS from a gene annotated with a specific function to views of its evolutionary context both with respect to other individual genes as well as to the genomic context in which it occurs.
 Now press the Gene Search button, or use the Next button or press →.",
        placement: 'bottom',
        element: SELECTOR.searchBtn,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        path: '/search/gene',
        content: 'All the legume genes in LIS have been annotated with functional descriptors based on a consistent set of homology-based methods. We\'ll use gene function as a query to limit the set of genes in the results.',
        placement: 'top',
        element: SELECTOR.descriptors,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'We can enter key terms from the expected description of the gene function in which we\'re interested here.',
        placement: 'bottom',
        element: SELECTOR.formFieldDescr,
        reflex: true,
        onShown: function(tour) {
          $(SELECTOR.formFieldDescr)[0].value=FOCUS_GENE_FUNCTION;
          $('#edit-description-op')[0].value='starts';
        },
      }, {
        title: 'Gene Tour: Filter by Species',
        content: "Supposing we are initially interested in the genes from Vigna radiata (mungbean), we would specify the five-letter species abbreviation 'vigra', composed of the first three letters of the genus and the first two letters of the species component of the scientific name.",
        onShown: function(tour) {
          $(SELECTOR.formFieldAbbrev)[0].value='vigra';
        },
        element: SELECTOR.formFieldAbbrev,
        placement: 'bottom',
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Then click "Apply" to apply the specified filters to the genes in the result.',
        placement: 'bottom',
        element: SELECTOR.submitBtn,
        reflex: true,
        onNext: function(tour) {
          $(SELECTOR.submitBtn)[0].click();
        }
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Please be patient, as we wait for the query results to be returned...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForContent(
            tour,
            function() {
              return $('tr.views-row-first td.views-field-description:contains("'+FOCUS_GENE_FUNCTION+'")')[0];
            }, 40000);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Search Results',
        content: "We've gotten paged results back for genes matching the given description in our target species.",
        element: SELECTOR.searchResult,
        placement: 'top',
        reflex: true,
       }, {
        title: 'Gene Tour: Functional description',
        content: "Notice that there is a subtle difference in the annotation of the genes, though they are all listed as belonging to the same gene family.",
        placement: 'top',
        element: SELECTOR.functionalDesc,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Family',
        content: "Following the link to the gene family will show you this gene in the context of a tree representing the orthologous, paralogous and homoeologous members of the family.",
        placement: 'left',
        reflex: true,
        element: SELECTOR.geneFamilyLink,
        onNext: function(tour) {
          $(SELECTOR.geneFamilyLink)[0].click();
        }
      }, {
        title: 'Gene Tour: Phylotree',
        content: 'Please be patient, as the phylogram chart loads...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
    var deferred = lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Phylotree',
        placement: 'left',
        content : 'Here is our gene again, surrounded by orthologues from other species. ',
        element : SELECTOR.phylotreeFocusProtein,
        onShow: function(tour) {
                    return lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
        },
        onShown: function(tour) {
          lisTours.fixHScroll();
          // hide the taxa and msa dialog for less clutter in this tour
                    if($(SELECTOR.taxaDialog).is(':visible')) {
                        $(SELECTOR.taxaButton)[0].click();
                    }
                    if($(SELECTOR.msaDialog).is(':visible')) {
                        $(SELECTOR.msaButton)[0].click();
                    }
        }
      }, /* commenting out this step which doesn't make sense with the new gene families; but I can't bear to delete it, in hopes that we may someday be able to illustrate mnoving from the legume-centric tree to a deeper phylogenetic perspective...
      {
        title: 'Gene Tour: Phylotree',
        placement: 'left',
        content : 'Notice that the two other instances of the gene family from mungbean are in a separate clade. This suggests that the gene was duplicated in an ancestral species and the two copies were retained in most of the species (possibly with subsequent duplications within some of the descendant species). This could be due to an important difference in function that evolved after the ancient duplication occurred.',
        element : SELECTOR.phylotreeAltProtein,
                onShow: function(tour) {
          lisTours.fixHScroll();
                    return lisTours.waitForSelector(tour, SELECTOR.phylotreeAltProtein);
                }
      }, */ {
        title: 'Gene Tour: Phylotree',
        placement: 'right',
        content : 'The nodes of the tree representing the genes (as well as the internal ancestral nodes) can be clicked for more options.',
        element : SELECTOR.phylotreeFocusProtein,
        reflex: true,
        onShow: function(tour) {
          lisTours.fixHScroll();
          return lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
        },
        onNext: function(tour) {
          $(SELECTOR.phylotreeFocusProtein).d3Click();
          return lisTours.waitForSelector(tour, SELECTOR.popup);
        }
      }, {
        title: 'Gene Tour: Gene Linkouts',
        content: 'We get a popup with a number of options relevant to the gene.',
        element: SELECTOR.popup,
        placement: 'left',
      }, {
        title: 'Gene Tour: Genomic Contexts',
        content: 'Let\'s follow the link for similar genomic contexts.',
        element: SELECTOR.contextViewerLink,
        reflex: true,
        placement: 'right',
        onNext: function(tour) {
          $(SELECTOR.contextViewerLink)[0].click();
        }
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Please be patient, as we wait for the page to load...',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForSelector(
            tour,
            'g.gene:has(:contains("'+FOCUS_GENE+'")) > path'
    );
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      },{
        title: 'Gene Tour: Genome Context Viewer',
        content: 'Our gene is front and center, highlighted among the neighboring genes from the same region on the chromosome. All genes are color coded according to the gene families to which they belong, and genomic segments with similar gene content are aligned to the track containing our search gene.',
        element: SELECTOR.contextFocusGene,
        placement: 'top',
        onNext: function(tour) {
          $(SELECTOR.familyLegendButton).click();
        },
      },{
        title: 'Gene Tour: Genome Context Viewer',
        content: 'Changing the track ordering from alphabetical (by Chromosome Name) to a measure of their similarity to the query track (Edit Distance) will affect both the micro- and macro-syntenic tracks.',
        element: SELECTOR.contextOrderControl,
        placement: 'top',
        onNext: function(tour) {
             var ctl = $(SELECTOR.contextOrderControl);
             ctl.val('distance');
             ctl[0].dispatchEvent(new Event("input", { bubbles: true }));
             ctl[0].dispatchEvent(new Event("change", { bubbles: true }));
        },
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'The tracks brought to the top due to their higher similarity to the query tend to span the length of the query track, though some are subject to rearrangements.',
        element: SELECTOR.contextFocusGene,
        placement: 'top',
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'Hover over the gene family to see all representatives highlighted in their syntenic contexts. Click the gene family for more information.',
        element: SELECTOR.contextLocus,
        placement: 'left',
        onNext: function(tour) {
          $(SELECTOR.contextLocus).d3Click();
        },
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'All representatives of the family present in the current view are listed.',
        element: SELECTOR.contextFocus,
        placement: 'right'
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'Following this link will take us back to the phylotree, with all of the syntenic members of the family highlighted.',
        element: SELECTOR.contextFamilyLink,
        placement: 'right',
        onNext: function(tour) {
          $(SELECTOR.contextFamilyLink)[0].click();
        },
      }, {
        title: 'Gene Tour: Phylotree',
        content: 'Please be patient, as the phylogram chart loads...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'We see that most of the members of the clade containing our gene were found by the syntenic context matching. The context viewer alignment parameters might be relaxed to try to include more of the clade and see how the gene content of the regions may have diverged more rapidly in these species.',
        element: SELECTOR.phylotreeFocusProtein,
        placement: 'top',
        onShown: function(tour) {
          lisTours.fixHScroll();
          // hide the taxa and msa dialog for less clutter in this tour
          if($(SELECTOR.taxaDialog).is(':visible')) {
              $(SELECTOR.taxaButton)[0].click();
          }
          if($(SELECTOR.msaDialog).is(':visible')) {
              $(SELECTOR.msaButton)[0].click();
          }
        }
      }, {
        title: 'Gene Tour: The End',
        content: 'Congratulations, you\'ve made it to the end of the Gene Tour. Please let us know if you have any suggestions on how to improve the tools used in this tour or the tour itself by using our Contact form. Now press End Tour.' ,
        element: SELECTOR.contact,
        reflex: true,
        placement: 'bottom'
     }
    ]
  });

  lisTours.register(tour);

}(window.__jquery));

<commit_msg>minor updates to fix breakage due to some changes in GCV<commit_after>'use strict';

(function(jQuery) {

  var $ = jQuery;

  var FOCUS_GENE_FAMILY = 'phytozome_10_2.59088092';
  var NEW_FOCUS_GENE_FAMILY = 'legfed_v1_0.L_JGH6XN';
  //var NEW_FOCUS_GENE_FAMILY = 'legfed_v1_0.L.FTX7K';
  var FOCUS_GENE = 'vigra.Vradi01g03360';
  var FOCUS_PROTEIN = FOCUS_GENE + '.1';
  var FOCUS_GENE_FUNCTION = 'gamma-glutamyl transpeptidase';
  var ALT_GENE = 'vigra.Vradi0091s00130';
  var ALT_PROTEIN = ALT_GENE + '.1';

  var SELECTOR = {
    welcome: '#site-name',
    searchBtn: "a:contains('Gene Search')",
    descriptors: 'th.views-field-description',
    formFieldDescr: '#edit-description',
    formFieldAbbrev: '#edit-abbreviation',
    submitBtn: '#edit-submit-gene',
    searchResult: 'th.views-field-name',
    functionalDesc: 'th.views-field-description',
    geneFamilyLink:'a[href*="'+FOCUS_GENE+'"]:contains("'+NEW_FOCUS_GENE_FAMILY+'")',
    phylotreeFocusProtein: '#phylogram g.legume:contains("'+ FOCUS_PROTEIN +'")',
    phylotreeAltProtein: '#phylogram g.legume:contains("'+ ALT_PROTEIN +'")',
    popup: '#node-dialog a:contains("Find similar")',
    contextViewerLink: "#node-dialog a[href*='lis_context_viewer']",
    contextFocusGene: 'path.point.focus:first',
    familyLegendButton: 'button:contains("Legend")',
    contextOrderControl: '#order',
    contextLocus: 'g.legend:has(:contains("'+NEW_FOCUS_GENE_FAMILY+'"))',
    contextFocus: 'h4:contains("'+NEW_FOCUS_GENE_FAMILY+'")',
    contextFamilyLink: 'a[href*="'+NEW_FOCUS_GENE_FAMILY+'"]:contains("Legume Information System")',
    contact: 'a:contains("Contact")',
    msaButton:        '#msa-toggle',
    msaDialog:        '#msa-dialog',
    taxaButton:       '#taxa-toggle',
    taxaDialog:       '#taxa-dialog',
  };

  $.fn.d3Click = function () {
    this.each(function (i, e) {
      var evt = new MouseEvent('click');
      e.dispatchEvent(evt);
    });
  };

  var tour = new Tour({
    name: 'gene-to-phylotree-to-context-viewer',
    keyboard: true,
    //debug: true,
    orphan: true,
    template: lisTours.template.noPrevBtnTemplate,
    steps : [
      {
        title: 'Gene Tour: Welcome to LIS!',
        content: 'Let\'s go the legumeinfo.org homepage, where the Gene Tour will begin.  Use the Next button or → (right arrow key) to advance the tour.',
        placement: 'bottom',
        element: SELECTOR.welcome,
        reflex: true,
      }, {
        title: 'Gene Tour: Getting started',
        path: '/home',
        content: "This tour will provide an example of navigating LIS from a gene annotated with a specific function to views of its evolutionary context both with respect to other individual genes as well as to the genomic context in which it occurs.
 Now press the Gene Search button, or use the Next button or press →.",
        placement: 'bottom',
        element: SELECTOR.searchBtn,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        path: '/search/gene',
        content: 'All the legume genes in LIS have been annotated with functional descriptors based on a consistent set of homology-based methods. We\'ll use gene function as a query to limit the set of genes in the results.',
        placement: 'top',
        element: SELECTOR.descriptors,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'We can enter key terms from the expected description of the gene function in which we\'re interested here.',
        placement: 'bottom',
        element: SELECTOR.formFieldDescr,
        reflex: true,
        onShown: function(tour) {
          $(SELECTOR.formFieldDescr)[0].value=FOCUS_GENE_FUNCTION;
          $('#edit-description-op')[0].value='starts';
        },
      }, {
        title: 'Gene Tour: Filter by Species',
        content: "Supposing we are initially interested in the genes from Vigna radiata (mungbean), we would specify the five-letter species abbreviation 'vigra', composed of the first three letters of the genus and the first two letters of the species component of the scientific name.",
        onShown: function(tour) {
          $(SELECTOR.formFieldAbbrev)[0].value='vigra';
        },
        element: SELECTOR.formFieldAbbrev,
        placement: 'bottom',
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Then click "Apply" to apply the specified filters to the genes in the result.',
        placement: 'bottom',
        element: SELECTOR.submitBtn,
        reflex: true,
        onNext: function(tour) {
          $(SELECTOR.submitBtn)[0].click();
        }
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Please be patient, as we wait for the query results to be returned...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForContent(
            tour,
            function() {
              return $('tr.views-row-first td.views-field-description:contains("'+FOCUS_GENE_FUNCTION+'")')[0];
            }, 40000);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Search Results',
        content: "We've gotten paged results back for genes matching the given description in our target species.",
        element: SELECTOR.searchResult,
        placement: 'top',
        reflex: true,
       }, {
        title: 'Gene Tour: Functional description',
        content: "Notice that there is a subtle difference in the annotation of the genes, though they are all listed as belonging to the same gene family.",
        placement: 'top',
        element: SELECTOR.functionalDesc,
        reflex: true,
      }, {
        title: 'Gene Tour: Gene Family',
        content: "Following the link to the gene family will show you this gene in the context of a tree representing the orthologous, paralogous and homoeologous members of the family.",
        placement: 'left',
        reflex: true,
        element: SELECTOR.geneFamilyLink,
        onNext: function(tour) {
          $(SELECTOR.geneFamilyLink)[0].click();
        }
      }, {
        title: 'Gene Tour: Phylotree',
        content: 'Please be patient, as the phylogram chart loads...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
    var deferred = lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Phylotree',
        placement: 'left',
        content : 'Here is our gene again, surrounded by orthologues from other species. ',
        element : SELECTOR.phylotreeFocusProtein,
        onShow: function(tour) {
                    return lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
        },
        onShown: function(tour) {
          lisTours.fixHScroll();
          // hide the taxa and msa dialog for less clutter in this tour
                    if($(SELECTOR.taxaDialog).is(':visible')) {
                        $(SELECTOR.taxaButton)[0].click();
                    }
                    if($(SELECTOR.msaDialog).is(':visible')) {
                        $(SELECTOR.msaButton)[0].click();
                    }
        }
      }, /* commenting out this step which doesn't make sense with the new gene families; but I can't bear to delete it, in hopes that we may someday be able to illustrate mnoving from the legume-centric tree to a deeper phylogenetic perspective...
      {
        title: 'Gene Tour: Phylotree',
        placement: 'left',
        content : 'Notice that the two other instances of the gene family from mungbean are in a separate clade. This suggests that the gene was duplicated in an ancestral species and the two copies were retained in most of the species (possibly with subsequent duplications within some of the descendant species). This could be due to an important difference in function that evolved after the ancient duplication occurred.',
        element : SELECTOR.phylotreeAltProtein,
                onShow: function(tour) {
          lisTours.fixHScroll();
                    return lisTours.waitForSelector(tour, SELECTOR.phylotreeAltProtein);
                }
      }, */ {
        title: 'Gene Tour: Phylotree',
        placement: 'right',
        content : 'The nodes of the tree representing the genes (as well as the internal ancestral nodes) can be clicked for more options.',
        element : SELECTOR.phylotreeFocusProtein,
        reflex: true,
        onShow: function(tour) {
          lisTours.fixHScroll();
          return lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
        },
        onNext: function(tour) {
          $(SELECTOR.phylotreeFocusProtein).d3Click();
          return lisTours.waitForSelector(tour, SELECTOR.popup);
        }
      }, {
        title: 'Gene Tour: Gene Linkouts',
        content: 'We get a popup with a number of options relevant to the gene.',
        element: SELECTOR.popup,
        placement: 'left',
      }, {
        title: 'Gene Tour: Genomic Contexts',
        content: 'Let\'s follow the link for similar genomic contexts.',
        element: SELECTOR.contextViewerLink,
        reflex: true,
        placement: 'right',
        onNext: function(tour) {
          $(SELECTOR.contextViewerLink)[0].click();
        }
      }, {
        title: 'Gene Tour: Gene Search',
        content: 'Please be patient, as we wait for the page to load...',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForSelector(
            tour,
            'g[data-gene="'+FOCUS_GENE+'"'
    );
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      },{
        title: 'Gene Tour: Genome Context Viewer',
        content: 'Our gene is front and center, highlighted among the neighboring genes from the same region on the chromosome. All genes are color coded according to the gene families to which they belong, and genomic segments with similar gene content are aligned to the track containing our search gene.',
        element: SELECTOR.contextFocusGene,
        placement: 'top',
        onNext: function(tour) {
          $(SELECTOR.familyLegendButton).click();
        },
      },{
        title: 'Gene Tour: Genome Context Viewer',
        content: 'Changing the track ordering from alphabetical (by Chromosome Name) to a measure of their similarity to the query track (Edit Distance) will affect both the micro- and macro-syntenic tracks.',
        element: SELECTOR.contextOrderControl,
        placement: 'top',
        onNext: function(tour) {
             var ctl = $(SELECTOR.contextOrderControl);
             ctl.val('distance');
             ctl[0].dispatchEvent(new Event("input", { bubbles: true }));
             ctl[0].dispatchEvent(new Event("change", { bubbles: true }));
        },
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'The tracks brought to the top due to their higher similarity to the query tend to span the length of the query track, though some are subject to rearrangements.',
        element: SELECTOR.contextFocusGene,
        placement: 'top',
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'Hover over the gene family to see all representatives highlighted in their syntenic contexts. Click the gene family for more information.',
        element: SELECTOR.contextLocus,
        placement: 'left',
        onNext: function(tour) {
          $(SELECTOR.contextLocus).d3Click();
        },
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'All representatives of the family present in the current view are listed.',
        element: SELECTOR.contextFocus,
        placement: 'right'
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'Following this link will take us back to the phylotree, with all of the syntenic members of the family highlighted.',
        element: SELECTOR.contextFamilyLink,
        placement: 'right',
        onNext: function(tour) {
          $(SELECTOR.contextFamilyLink)[0].click();
        },
      }, {
        title: 'Gene Tour: Phylotree',
        content: 'Please be patient, as the phylogram chart loads...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          var deferred = lisTours.waitForSelector(tour, SELECTOR.phylotreeFocusProtein);
          // advance automatically to next step when done loading
          deferred.then(function() {
            tour.next();
          });
          return deferred.promise();
        }
      }, {
        title: 'Gene Tour: Gene Family Focus',
        content: 'We see that most of the members of the clade containing our gene were found by the syntenic context matching. The context viewer alignment parameters might be relaxed to try to include more of the clade and see how the gene content of the regions may have diverged more rapidly in these species.',
        element: SELECTOR.phylotreeFocusProtein,
        placement: 'top',
        onShown: function(tour) {
          lisTours.fixHScroll();
          // hide the taxa and msa dialog for less clutter in this tour
          if($(SELECTOR.taxaDialog).is(':visible')) {
              $(SELECTOR.taxaButton)[0].click();
          }
          if($(SELECTOR.msaDialog).is(':visible')) {
              $(SELECTOR.msaButton)[0].click();
          }
        }
      }, {
        title: 'Gene Tour: The End',
        content: 'Congratulations, you\'ve made it to the end of the Gene Tour. Please let us know if you have any suggestions on how to improve the tools used in this tour or the tour itself by using our Contact form. Now press End Tour.' ,
        element: SELECTOR.contact,
        reflex: true,
        placement: 'bottom'
     }
    ]
  });

  lisTours.register(tour);

}(window.__jquery));

<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2014 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

(function() {

  describe('Web handler', function() {
    var mockXhr, utils, webHandler, webModule, Y;
    var requirements = ['juju-env-web-handler', 'juju-tests-utils'];

    before(function(done) {
      // Set up the YUI instance, the test utils and the web namespace.
      Y = YUI(GlobalConfig).use(requirements, function(Y) {
        utils = Y.namespace('juju-tests.utils');
        webModule = Y.namespace('juju.environments.web');
        done();
      });
    });

    beforeEach(function() {
      // Instantiate a web handler and set up an XMLHttpRequest mock.
      webHandler = new webModule.WebHandler();
      var context = XMLHttpRequest.prototype;
      mockXhr = {
        addEventListener: utils.makeStubMethod(context, 'addEventListener'),
        open: utils.makeStubMethod(context, 'open'),
        setRequestHeader: utils.makeStubMethod(context, 'setRequestHeader'),
        send: utils.makeStubMethod(context, 'send'),
        removeEventListener: utils.makeStubMethod(
            context, 'removeEventListener')
      };
    });

    afterEach(function() {
      webHandler.destroy();
      // Reset all the method mocks.
      Y.each(mockXhr, function(value) {
        value.reset();
      });
    });

    // Ensure the progress event is correctly handled.
    var assertProgressHandled = function(progressCallback) {
      // Retrieve the registered progress handler.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      // Set up a progress event and call the progress handler.
      var evt = {type: 'progress'};
      progressHandler(evt);
      // The progress callback has been correctly called.
      assert.strictEqual(progressCallback.callCount(), 1);
      assert.deepEqual(progressCallback.lastArguments(), [evt]);
      // The event listeners are only removed when the completed callback is
      // called.
      assert.strictEqual(mockXhr.removeEventListener.called(), false);
    };

    // Ensure the completed event is correctly handled.
    var assertCompletedHandled = function(completedCallback) {
      // Retrieve the registered handlers.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      var completedHandler = args[1][1];
      // Set up a load event and call the completed handler.
      var evt = {type: 'load'};
      completedHandler(evt);
      // The completion callback has been correctly called.
      assert.strictEqual(completedCallback.callCount(), 1);
      assert.deepEqual(completedCallback.lastArguments(), [evt]);
      // The event listeners have been removed.
      assert.strictEqual(mockXhr.removeEventListener.callCount(), 2);
      args = mockXhr.removeEventListener.allArguments();
      assert.deepEqual(args[0], ['progress', progressHandler]);
      assert.deepEqual(args[1], ['load', completedHandler]);
    };

    describe('sendPostRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPostRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 2);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['POST', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendPutRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPutRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 2);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['PUT', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendGetRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?url=local:trusty/django-42';
        // Make a POST request.
        webHandler.sendGetRequest(
            path, null, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 2);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['GET', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 1);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.lengthOf(mockXhr.send.lastArguments(), 0);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    it('defines a function which helps creating auth headers', function() {
      var header = webHandler._createAuthorizationHeader('myuser', 'mypasswd');
      assert.strictEqual(header, 'Basic bXl1c2VyOm15cGFzc3dk');
    });

    describe('getUrl', function() {
      it('returns a complete URL based on the given credentials', function() {
        var url = webHandler.getUrl('/my/path', 'myuser', 'mypassword');
        var expectedUrl = 'http://myuser:mypassword@' +
            window.location.host + '/my/path';
        assert.strictEqual(url, expectedUrl);
      });
    });

  });

})();
<commit_msg>Update webhandler tests to check for the new event listeners.<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2014 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

(function() {

  describe('Web handler', function() {
    var mockXhr, utils, webHandler, webModule, Y;
    var requirements = ['juju-env-web-handler', 'juju-tests-utils'];

    before(function(done) {
      // Set up the YUI instance, the test utils and the web namespace.
      Y = YUI(GlobalConfig).use(requirements, function(Y) {
        utils = Y.namespace('juju-tests.utils');
        webModule = Y.namespace('juju.environments.web');
        done();
      });
    });

    beforeEach(function() {
      // Instantiate a web handler and set up an XMLHttpRequest mock.
      webHandler = new webModule.WebHandler();
      var context = XMLHttpRequest.prototype;
      mockXhr = {
        addEventListener: utils.makeStubMethod(context, 'addEventListener'),
        open: utils.makeStubMethod(context, 'open'),
        setRequestHeader: utils.makeStubMethod(context, 'setRequestHeader'),
        send: utils.makeStubMethod(context, 'send'),
        removeEventListener: utils.makeStubMethod(
            context, 'removeEventListener')
      };
    });

    afterEach(function() {
      webHandler.destroy();
      // Reset all the method mocks.
      Y.each(mockXhr, function(value) {
        value.reset();
      });
    });

    // Ensure the progress event is correctly handled.
    var assertProgressHandled = function(progressCallback) {
      // Retrieve the registered progress handler.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      // Set up a progress event and call the progress handler.
      var evt = {type: 'progress'};
      progressHandler(evt);
      // The progress callback has been correctly called.
      assert.strictEqual(progressCallback.callCount(), 1);
      assert.deepEqual(progressCallback.lastArguments(), [evt]);
      // The event listeners are only removed when the completed callback is
      // called.
      assert.strictEqual(mockXhr.removeEventListener.called(), false);
    };

    // Ensure the completed event is correctly handled.
    var assertCompletedHandled = function(completedCallback) {
      // Retrieve the registered handlers.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      var completedHandler = args[1][1];
      // Set up a load event and call the completed handler.
      var evt = {type: 'load'};
      completedHandler(evt);
      // The completion callback has been correctly called.
      assert.strictEqual(completedCallback.callCount(), 1);
      assert.deepEqual(completedCallback.lastArguments(), [evt]);
      // The event listeners have been removed.
      assert.strictEqual(mockXhr.removeEventListener.callCount(), 3);
      args = mockXhr.removeEventListener.allArguments();
      assert.deepEqual(args[0], ['progress', progressHandler]);
      assert.deepEqual(args[1], ['error', completedHandler]);
      assert.deepEqual(args[2], ['load', completedHandler]);
    };

    describe('sendPostRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPostRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['POST', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendPutRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPutRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['PUT', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendGetRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?url=local:trusty/django-42';
        // Make a POST request.
        webHandler.sendGetRequest(
            path, null, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['GET', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 1);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.lengthOf(mockXhr.send.lastArguments(), 0);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    it('defines a function which helps creating auth headers', function() {
      var header = webHandler._createAuthorizationHeader('myuser', 'mypasswd');
      assert.strictEqual(header, 'Basic bXl1c2VyOm15cGFzc3dk');
    });

    describe('getUrl', function() {
      it('returns a complete URL based on the given credentials', function() {
        var url = webHandler.getUrl('/my/path', 'myuser', 'mypassword');
        var expectedUrl = 'http://myuser:mypassword@' +
            window.location.host + '/my/path';
        assert.strictEqual(url, expectedUrl);
      });
    });

  });

})();
<|endoftext|>


<commit_before>
var inherit;
(function (global, exports) {

    /**
     *
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Function} [baseClass] The prototype to inherit from
     *
     * @return {Function} returns a constructor function describing the class
     */
    inherit = function(classDefinition, baseClass) {
        baseClass = baseClass || Object;

        var newClass = function() {
            if (this.ctor) {
                this.ctor.apply(this, arguments);
            }
        };

        if (baseClass.constructor == Function) {

            function Inheritance(){}
            Inheritance.prototype = baseClass.prototype;

            newClass.prototype = new Inheritance();
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass.prototype;

        } else {
            newClass.prototype = baseClass;
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass;
        }

        for (var publicMethod in classDefinition) {
            if (classDefinition.hasOwnProperty(publicMethod)) {
                var baseFunction = newClass.prototype[publicMethod];
                newClass.prototype[publicMethod] = classDefinition[publicMethod];
                newClass.prototype[publicMethod].baseImplementation = baseFunction;
            }
        }

        return newClass;

    };

    /**
     *
     * @param classDefinition The definition for the prototype methods
     *
     * @return {Function} returns a constructor function describing the class
     */
    Function.prototype.inherit = function(classDefinition) {
        return inherit(classDefinition, this);
    };

    Function.prototype.callBase = function() {
        var args = Array.prototype.slice.call(arguments);
        var that = args.shift();

        if (that && that.base) {
            var caller = arguments.callee.caller;

            if (this == caller) {
                return this.baseImplementation(that, args);
            } else {
                return this.apply(that, args);
            }
        } else {
            throw "base not definied";
        }
    };

    /**
     * @property {Function} base class
     */
    inherit.Base = inherit({
        ctor: function(){}
    });

    exports.inherit = inherit;

})(this, typeof exports === "undefined" ? this : exports);<commit_msg>implemented this.callBase method to call the base method with the same or different parameters<commit_after>var inherit;
(function (global, exports) {

    /**
     *
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Function} [baseClass] The prototype to inherit from
     *
     * @return {Function} returns a constructor function describing the class
     */
    inherit = function (classDefinition, baseClass) {
        baseClass = baseClass || Object;

        var newClass = function () {
            if (this.ctor) {
                this.ctor.apply(this, arguments);
            }
        };

        if (baseClass.constructor == Function) {

            function Inheritance() {
            }

            Inheritance.prototype = baseClass.prototype;

            newClass.prototype = new Inheritance();
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass.prototype;

        } else {
            newClass.prototype = baseClass;
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass;
        }

        for (var publicMethod in classDefinition) {
            if (classDefinition.hasOwnProperty(publicMethod)) {
                var baseFunction = newClass.prototype[publicMethod];
                newClass.prototype[publicMethod] = classDefinition[publicMethod];
                newClass.prototype[publicMethod].baseImplementation = baseFunction;
            }
        }

        newClass.prototype.callBase = inherit.callBase;

        return newClass;

    };

    inherit.callBase = function () {
        var args = Array.prototype.slice.call(arguments);

        if (args.length == 0) {
            // use arguments from call
            args = Array.prototype.slice.call(arguments.callee.caller.arguments);
        }

        return arguments.callee.caller.baseImplementation.apply(this, args);
    };

    /**
     *
     * @param classDefinition The definition for the prototype methods
     *
     * @return {Function} returns a constructor function describing the class
     */
    Function.prototype.inherit = function (classDefinition) {
        return inherit(classDefinition, this);
    };

    Function.prototype.callBase = function () {
        var args = Array.prototype.slice.call(arguments);
        var that = args.shift();

        if (that && that.base) {
            var caller = arguments.callee.caller;

            if (this == caller) {
                return this.baseImplementation.apply(that, args);
            } else {
                return this.apply(that, args);
            }
        } else {
            throw "base not definied";
        }
    };

    /**
     * @property {Function} base class
     */
    inherit.Base = inherit({
        ctor: function () {
        }
    });

    exports.inherit = inherit;

})(this, typeof exports === "undefined" ? this : exports);<|endoftext|>


<commit_before>
/*
  This script will initialize a local Mongo database
  on your machine so you can do development work.

  IMPORTANT: You should make sure the

      local_name

  variable matches its value in app.js  Otherwise, you'll have
  initialized the wrong database.
*/

var mongoose = require('mongoose');
var models   = require('./models');

// Connect to the Mongo database, whether locally or on Heroku
// MAKE SURE TO CHANGE THE NAME FROM 'lab7' TO ... IN OTHER PROJECTS
var local_name = 'cs247project';
var local_uri  = 'mongodb://localhost/' + local_name
var database_uri = process.env.MONGOLAB_URI || local_uri
mongoose.connect(database_uri);

// Do the initialization here

// Step 1: load the JSON data

// Step 2: Remove all existing documents
models.Match
  .find()
  .remove()
  .exec(onceClear); // callback to continue at

// Step 3: load the data from the JSON file
function onceClear(err) {
  if(err) console.log(err);
  models.NoMatch
    .find()
    .remove()
    .exec(onceClear2);
  console.log("done1");
}

function onceClear2(err) {
  if(err) console.log(err);
  models.Notification
    .find()
    .remove()
    .exec(onceClear3);
  console.log("done2");
}

function onceClear3(err) {
  var match2 = new models.Match({"uid1": "10152423734788293", "uid2": "696436097061985", "recommenders": "Jordan Shelton,Aubriana Menendez,Victoria Smith,Joe Lee,Helena Scutt", "numRecs": 5});
  match2.save(function(err, proj) {
    var match3 = new models.Match({"uid1": "10152423734788293", "uid2": "637148899698075", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
    match3.save(function(err, proj) {
      var match4 = new models.Match({"uid1": "10152423734788293", "uid2": "10152002738066150", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
      match4.save(function(err, proj) {
          var match = new models.Match({"uid1": "10152423734788293", "uid2": "10203924091048701", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
          match.save(function(err, proj) {
          if(err) console.log(err);
          console.log("done3");
          var not = new models.Notification({"uid": "10152423734788293", "type": "message", "seen": false, "from": "33333333"})
          not.save(function(err, proj) {
            if(err) console.log(err);
            console.log("done4");
            mongoose.connection.close();
          });
        });
      });
    });
  });
}<commit_msg>all committed<commit_after>
/*
  This script will initialize a local Mongo database
  on your machine so you can do development work.

  IMPORTANT: You should make sure the

      local_name

  variable matches its value in app.js  Otherwise, you'll have
  initialized the wrong database.
*/

var mongoose = require('mongoose');
var models   = require('./models');

// Connect to the Mongo database, whether locally or on Heroku
// MAKE SURE TO CHANGE THE NAME FROM 'lab7' TO ... IN OTHER PROJECTS
var local_name = 'cs247project';
var local_uri  = 'mongodb://localhost/' + local_name
var database_uri = process.env.MONGOLAB_URI || local_uri
mongoose.connect(database_uri);

// Do the initialization here

// Step 1: load the JSON data

// Step 2: Remove all existing documents
models.Match
  .find()
  .remove()
  .exec(onceClear); // callback to continue at

// Step 3: load the data from the JSON file
function onceClear(err) {
  if(err) console.log(err);
  models.NoMatch
    .find()
    .remove()
    .exec(onceClear2);
  console.log("done1");
}

function onceClear2(err) {
  if(err) console.log(err);
  models.Notification
    .find()
    .remove()
    .exec(onceClear3);
  console.log("done2");
}

function onceClear3(err) {
  var match2 = new models.Match({"uid1": "2415271352488", "uid2": "696436097061985", "recommenders": "Jordan Shelton,Aubriana Menendez,Victoria Smith,Joe Lee,Helena Scutt", "numRecs": 5});
  match2.save(function(err, proj) {
    var match3 = new models.Match({"uid1": "2415271352488", "uid2": "637148899698075", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
    match3.save(function(err, proj) {
      var match4 = new models.Match({"uid1": "2415271352488", "uid2": "10152002738066150", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
      match4.save(function(err, proj) {
          var match = new models.Match({"uid1": "2415271352488", "uid2": "10203924091048701", "recommenders": "hello,hi,conner,kennan,jordan", "numRecs": 5});
          match.save(function(err, proj) {
          if(err) console.log(err);
          console.log("done3");
          var not = new models.Notification({"uid": "2415271352488", "type": "message", "seen": false, "from": "637148899698075"})
          not.save(function(err, proj) {
            if(err) console.log(err);
            console.log("done4");
            mongoose.connection.close();
          });
        });
      });
    });
  });
}<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */
sap.ui.define([
		"sap/ui/integration/library",
		"sap/f/library",
		"sap/ui/dom/includeScript",
		"sap/f/cards/BaseContent",
		"sap/ui/integration/thirdparty/adaptivecards",
		"sap/f/cards/adaptivecards/elements/UI5InputText",
		"sap/f/cards/adaptivecards/elements/UI5InputNumber",
		"sap/f/cards/adaptivecards/elements/UI5InputChoiceSet",
		"sap/f/cards/adaptivecards/elements/UI5InputTime",
		"sap/f/cards/adaptivecards/elements/UI5InputDate",
		"sap/f/cards/adaptivecards/elements/UI5InputToggle",
		"sap/f/cards/adaptivecards/overwrites/ActionRender",
		"sap/f/cards/adaptivecards/elements/hostConfig"
	],
	function (integrationLibrary, fLibrary, includeScript, BaseContent, AdaptiveCards, UI5InputText, UI5InputNumber, UI5InputChoiceSet, UI5InputTime, UI5InputDate, UI5InputToggle, ActionRender, HostConfig) {
		"use strict";

		/**
		 * Constructor for a new AdaptiveContent.
		 *
		 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
		 * @param {object} [mSettings] Initial settings for the new control
		 *
		 * @class
		 * A control that is a wrapper of Microsoft's AdaptiveCard and allows its creation based on a configuration.
		 *
		 * @extends sap.f.cards.BaseContent
		 *
		 * @author SAP SE
		 * @version ${version}
		 *
		 * @constructor
		 * @private
		 * @since 1.74
		 * @alias sap.f.cards.AdaptiveContent
		 */
		var AdaptiveContent = BaseContent.extend("sap.f.cards.AdaptiveContent", {
			renderer: {
				apiVersion: 2,
				render: function (oRm, oControl) {
					var oParentRenderer = BaseContent.getMetadata().getRenderer();

					return oParentRenderer.render.apply(this, arguments);
				}
			}
		});

		AdaptiveContent.prototype.init = function () {
			this._setupAdaptiveCardDependency();
			this._loadDependencies();
		};

		/**
		 * Setter for configuring a sap.f.cards.AdaptiveContent.
		 *
		 * @public
		 * @param {Object} oConfiguration Configuration object used to create the internal list.
		 * @returns {sap.f.cards.AdaptiveContent} Pointer to the control instance to allow method chaining.
		 */
		AdaptiveContent.prototype.setConfiguration = function (oConfiguration) {
			this._oCardConfig = oConfiguration;
			this._renderMSCardContent();
		};

		AdaptiveContent.prototype.onAfterRendering = function () {
			this._renderMSCardContent();
		};

		/**
		 * Init MS AdaptiveCard and patch its default renders with UI5 WebComponents
		 *
		 * @private
		 */
		AdaptiveContent.prototype._setupAdaptiveCardDependency = function () {
			this.adaptiveCardInstance = new AdaptiveCards.AdaptiveCard();

			this._doMSCardsOverwrites();
			this._adjustHostConfig();
			this._handleActions();
			this._replaceElements();
			this._isRtl();
		};

		/**
		 * Replace Buttons with UI5-Buttons in MS Cards actions
		 *
		 * @private
		 */
		AdaptiveContent.prototype._doMSCardsOverwrites = function () {
			AdaptiveCards.Action.prototype.render = ActionRender;
		};

		/**
		 * Adjust elements' styling with custom values
		 *
		 * @private
		 */
		AdaptiveContent.prototype._adjustHostConfig = function () {
			this.adaptiveCardInstance.hostConfig = new AdaptiveCards.HostConfig(HostConfig);
		};

		/**
		 * Synchronize UI5 and AdaptiveCards RTL mode.
		 *
		 * @private
		 */
		AdaptiveContent.prototype._isRtl = function () {
			this.adaptiveCardInstance.isRtl = function () {
				return sap.ui.getCore().getConfiguration().getRTL();
			};
		};

		/**
		 * Propagate MS Cards Actions out of the Card
		 *
		 * @private
		 */
		AdaptiveContent.prototype._handleActions = function () {
			this.adaptiveCardInstance.onExecuteAction = function (oAction) {
				var sType, oPayload;

				if (oAction instanceof AdaptiveCards.OpenUrlAction) {
					oPayload = oAction.url;
					sType = integrationLibrary.CardActionType.Navigation;
				} else if (oAction instanceof AdaptiveCards.SubmitAction) {
					oPayload = oAction.data;
					sType = integrationLibrary.CardActionType.Submit;
				} else {
					// The other types of actions are entirely internal
					// and would not make sense to be bubbled outside the Card.
					return;
				}

				this.fireEvent("action", {
					actionSource: this,
					manifestParameters: oPayload,
					type: sType
				});
			}.bind(this);
		};

		/**
		 * Replaces MS Cards Elements with UI5WebComponents
		 *
		 * @private
		 */
		AdaptiveContent.prototype._replaceElements = function () {
			// Input.Text
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Text");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Text", function () {
				return new UI5InputText();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Number");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Number", function () {
				return new UI5InputNumber();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.ChoiceSet");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.ChoiceSet", function () {
				return new UI5InputChoiceSet();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Time");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Time", function () {
				return new UI5InputTime();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Date");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Date", function () {
				return new UI5InputDate();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Toggle");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Toggle", function () {
				return new UI5InputToggle();
			});
		};

		/**
		 * Renders a Card
		 *
		 * @private
		 */
		AdaptiveContent.prototype._renderMSCardContent = function () {
			var oDom = this.$();
			if (this.adaptiveCardInstance && this._oCardConfig && oDom && oDom.size()) {
				this.adaptiveCardInstance.parse(this._oCardConfig);
				oDom.html(this.adaptiveCardInstance.render());
			}
		};

		/**
		 * Load UI5 WebComponents
		 *
		 * We don't need to think about when the WebComponents dependency would be loaded.
		 * If preloaded, then all elements would be rendered properly. If loaded at a later time,
		 * then "the placeholders" would be patched and the WebComponents would be build later.
		 *
		 * @private
		 */
		AdaptiveContent.prototype._loadDependencies = function () {
			// Check weather the WebComponents are already loaded. We don't need to fetch the scripts again
			if (document.querySelector("#webcomponents-loader")) {
				return;
			}

			includeScript({
				id: "webcomponents-loader",
				url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/webcomponentsjs/webcomponents-loader.js")
			});
			includeScript({
				id: "webcomponents-bundle",
				attributes: {type: "module"},
				url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/bundle.esm.js")
			});
			includeScript({
				id: "webcomponents-bundle-es5",
				attributes: {nomodule: "nomodule"},
				url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/bundle.es5.js")
			});
		};

		return AdaptiveContent;
	}
);<commit_msg>[INTERNAL] sap.f.cards.AdaptiveContent: Web Components loading on IE & Edge Fixed<commit_after>/*!
 * ${copyright}
 */
sap.ui.define([
		"sap/ui/integration/library",
		"sap/f/library",
		"sap/ui/dom/includeScript",
		"sap/f/cards/BaseContent",
		"sap/ui/integration/thirdparty/adaptivecards",
		"sap/f/cards/adaptivecards/elements/UI5InputText",
		"sap/f/cards/adaptivecards/elements/UI5InputNumber",
		"sap/f/cards/adaptivecards/elements/UI5InputChoiceSet",
		"sap/f/cards/adaptivecards/elements/UI5InputTime",
		"sap/f/cards/adaptivecards/elements/UI5InputDate",
		"sap/f/cards/adaptivecards/elements/UI5InputToggle",
		"sap/f/cards/adaptivecards/overwrites/ActionRender",
		"sap/f/cards/adaptivecards/elements/hostConfig"
	],
	function (integrationLibrary, fLibrary, includeScript, BaseContent, AdaptiveCards, UI5InputText, UI5InputNumber, UI5InputChoiceSet, UI5InputTime, UI5InputDate, UI5InputToggle, ActionRender, HostConfig) {
		"use strict";

		/**
		 * Constructor for a new AdaptiveContent.
		 *
		 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
		 * @param {object} [mSettings] Initial settings for the new control
		 *
		 * @class
		 * A control that is a wrapper of Microsoft's AdaptiveCard and allows its creation based on a configuration.
		 *
		 * @extends sap.f.cards.BaseContent
		 *
		 * @author SAP SE
		 * @version ${version}
		 *
		 * @constructor
		 * @private
		 * @since 1.74
		 * @alias sap.f.cards.AdaptiveContent
		 */
		var AdaptiveContent = BaseContent.extend("sap.f.cards.AdaptiveContent", {
			renderer: {
				apiVersion: 2,
				render: function (oRm, oControl) {
					var oParentRenderer = BaseContent.getMetadata().getRenderer();

					return oParentRenderer.render.apply(this, arguments);
				}
			}
		});

		AdaptiveContent.prototype.init = function () {
			this._setupAdaptiveCardDependency();
			this._loadDependencies();
		};

		/**
		 * Setter for configuring a sap.f.cards.AdaptiveContent.
		 *
		 * @public
		 * @param {Object} oConfiguration Configuration object used to create the internal list.
		 * @returns {sap.f.cards.AdaptiveContent} Pointer to the control instance to allow method chaining.
		 */
		AdaptiveContent.prototype.setConfiguration = function (oConfiguration) {
			this._oCardConfig = oConfiguration;
			this._renderMSCardContent();
		};

		AdaptiveContent.prototype.onAfterRendering = function () {
			this._renderMSCardContent();
		};

		/**
		 * Init MS AdaptiveCard and patch its default renders with UI5 WebComponents
		 *
		 * @private
		 */
		AdaptiveContent.prototype._setupAdaptiveCardDependency = function () {
			this.adaptiveCardInstance = new AdaptiveCards.AdaptiveCard();

			this._doMSCardsOverwrites();
			this._adjustHostConfig();
			this._handleActions();
			this._replaceElements();
			this._isRtl();
		};

		/**
		 * Replace Buttons with UI5-Buttons in MS Cards actions
		 *
		 * @private
		 */
		AdaptiveContent.prototype._doMSCardsOverwrites = function () {
			AdaptiveCards.Action.prototype.render = ActionRender;
		};

		/**
		 * Adjust elements' styling with custom values
		 *
		 * @private
		 */
		AdaptiveContent.prototype._adjustHostConfig = function () {
			this.adaptiveCardInstance.hostConfig = new AdaptiveCards.HostConfig(HostConfig);
		};

		/**
		 * Synchronize UI5 and AdaptiveCards RTL mode.
		 *
		 * @private
		 */
		AdaptiveContent.prototype._isRtl = function () {
			this.adaptiveCardInstance.isRtl = function () {
				return sap.ui.getCore().getConfiguration().getRTL();
			};
		};

		/**
		 * Propagate MS Cards Actions out of the Card
		 *
		 * @private
		 */
		AdaptiveContent.prototype._handleActions = function () {
			this.adaptiveCardInstance.onExecuteAction = function (oAction) {
				var sType, oPayload;

				if (oAction instanceof AdaptiveCards.OpenUrlAction) {
					oPayload = oAction.url;
					sType = integrationLibrary.CardActionType.Navigation;
				} else if (oAction instanceof AdaptiveCards.SubmitAction) {
					oPayload = oAction.data;
					sType = integrationLibrary.CardActionType.Submit;
				} else {
					// The other types of actions are entirely internal
					// and would not make sense to be bubbled outside the Card.
					return;
				}

				this.fireEvent("action", {
					actionSource: this,
					manifestParameters: oPayload,
					type: sType
				});
			}.bind(this);
		};

		/**
		 * Replaces MS Cards Elements with UI5WebComponents
		 *
		 * @private
		 */
		AdaptiveContent.prototype._replaceElements = function () {
			// Input.Text
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Text");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Text", function () {
				return new UI5InputText();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Number");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Number", function () {
				return new UI5InputNumber();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.ChoiceSet");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.ChoiceSet", function () {
				return new UI5InputChoiceSet();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Time");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Time", function () {
				return new UI5InputTime();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Date");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Date", function () {
				return new UI5InputDate();
			});
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.unregisterType("Input.Toggle");
			AdaptiveCards.AdaptiveCard.elementTypeRegistry.registerType("Input.Toggle", function () {
				return new UI5InputToggle();
			});
		};

		/**
		 * Renders a Card
		 *
		 * @private
		 */
		AdaptiveContent.prototype._renderMSCardContent = function () {
			var oDom = this.$();
			if (this.adaptiveCardInstance && this._oCardConfig && oDom && oDom.size()) {
				this.adaptiveCardInstance.parse(this._oCardConfig);
				oDom.html(this.adaptiveCardInstance.render());
			}
		};

		/**
		 * Load UI5 WebComponents
		 *
		 * We don't need to think about when the WebComponents dependency would be loaded.
		 * If preloaded, then all elements would be rendered properly. If loaded at a later time,
		 * then "the placeholders" would be patched and the WebComponents would be build later.
		 *
		 * @private
		 */
		AdaptiveContent.prototype._loadDependencies = function () {
			// Check weather the WebComponents are already loaded. We don't need to fetch the scripts again
			if (document.querySelector("#webcomponents-loader")) {
				return;
			}

			includeScript({
				id: "webcomponents-loader",
				url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/webcomponentsjs/webcomponents-loader.js")
			});

			// The Web Components need to wait a bit for the Web Components loader and eventual polyfills
			// to get ready. There's a CustomEvent for which we need to subscribe.
			document.addEventListener("WebComponentsReady", function () {
				includeScript({
					id: "webcomponents-bundle",
					attributes: {type: "module"},
					url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/bundle.esm.js")
				});
				includeScript({
					id: "webcomponents-bundle-es5",
					attributes: {nomodule: "nomodule"},
					url: sap.ui.require.toUrl("sap/ui/integration/thirdparty/webcomponents/bundle.es5.js")
				});
			});
		};

		return AdaptiveContent;
	}
);<|endoftext|>