<commit_before>function debugSleep(ms) {
    if (Meteor.settings.debug) {
        Meteor._sleepForMs(ms);
    }
}

function clearFilter(inFilter) {
    inFilter = inFilter || {};
    const filter = {};
    Object.keys(inFilter).forEach((k) => {
        if (inFilter[k]) {
            filter[k] = inFilter[k]
        }
    });
    return filter;
}

function generateOptions(limit = 0, omitFields = [], sortField = "submitted", reverse = true) {
    const options = {};
    if (limit && limit > 0) {
        options.limit = limit;
    }
    if (omitFields && omitFields.length) {
        options.fields = {};
        for (let f of omitFields) {
            options.fields[f] = false;
        }
    }
    if (sortField) {
        options.sort = {};
        options.sort[sortField] = reverse ? -1 : 1;
    }
    return options;
}

Meteor.smartPublish('articles', function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("articles", "imageId", doc => Images.find(doc.imageId));
    return Articles.find(filter, generateOptions(limit, ["text"], "createdAt"));
});

Meteor.smartPublish("article", function (slug) {
    this.addDependency("articles", "imageId", doc => Images.find(doc.imageId));
    return Articles.find({slug: slug});
});

Meteor.smartPublish("tempArticle", function () {
    const userId = this.userId || "";
    if (userId && Roles.userIsInRole(userId, ['admin'])) {
        return TempArticles.find({authorId: userId});
    }
    return [];
});

Meteor.publish("tags", function () {
    return Tags.find();
});

Meteor.smartPublish('jobs', function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("jobs", "companyName", doc => Companies.find({name: doc.companyName}));
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Jobs.find(filter, generateOptions(limit, ["description"], "createdAt"));
});

Meteor.smartPublish("job", function (slug) {
    this.addDependency("jobs", "companyName", doc => Companies.find({name: doc.companyName}));
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Jobs.find({slug: slug});
});

Meteor.smartPublish("companies", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("companies", "imageId", doc =>  Images.find(doc.imageId));
    return Companies.find(filter, generateOptions(limit, ["text"]));
});

Meteor.publish("companyNames", function () {
    return Companies.find({}, {fields: {name: 1}});
});

Meteor.smartPublish("company", function (slug) {
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Companies.find({slug: slug});
});

Meteor.publish("featuredCompanies", function () {
    return FeaturedCompanies.find({});
});

Meteor.smartPublish("projects", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    this.addDependency("projects", "listImageId", doc => doc.listImageId ? Images.find(doc.listImageId) : []);
    return Projects.find(filter, generateOptions(limit, ["description"], "createdAt", true));
});

Meteor.smartPublish("project", function (slug) {
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    if (this.userId) {
        this.addDependency("projects", "_id",
                doc => Participations.find({authorId: this.userId, projectId: doc._id}))
    }
    return Projects.find({slug: slug});
});

Meteor.publish("featuredProjects", function (limit) {
    return Projects.find({}, generateOptions(limit, ["description"], "importance", true));
});

Meteor.smartPublish("spEvents", function (limit, filter) {
    filter = clearFilter(filter);
    filter['$or'] = [{closed: {'$exists': false}}, {closed: false}];
    return SpEvents.find(filter, generateOptions(limit, ["text", "additionalText"]));
});

Meteor.smartPublish("spEvent", function (slug) {
    const userId = this.userId || "";
    return [
        SpEvents.find({slug: slug}),
        SpEventRegistrations.find({userId: userId})
    ]
});

Meteor.smartPublish("spEventRegistrations", function (slug) {
    const userId = this.userId || "";
    if (userId && Roles.userIsInRole(userId, ['admin'])) {
        this.addDependency("spEvents", "_id", doc => SpEventRegistrations.find({eventId: doc._id}));
        this.addDependency("spEventRegistrations", "userId",
                doc => Meteor.users.find({_id: doc.userId}));
        return SpEvents.find({slug: slug});
    }
    else {
        return [];
    }
});

Meteor.smartPublish("profile", function (username) {
    this.addDependency("users", "profile.photoId", doc => Avatars.find(doc.profile.photoId));
    this.addDependency("users", "_id", doc => Participations.find({authorId: doc._id}));
    this.addDependency("participations", "projectId",
            doc => Projects.find(doc.projectId, {fields: {name: 1, slug: 1, imageId: 1}}));
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    const user = Meteor.users.findOne({username: username});
    if (user.profile && user.profile.isPrivate && this.userId !== user.id) {
        return Meteor.users.find({username: username},
            {fields: {"_id": 1, "username": 1, "profile.firstName": 1, "profile.lastName": 1}});
    }
    else {
        return Meteor.users.find({username: username}, {fields: {"_id": 1, "username": 1, profile: 1}});
    }
});

Meteor.publish('countries', function () {
    return Locations.find({});
});

Meteor.publish('professions', function () {
    return Professions.find({});
});

Meteor.smartPublish("projectComments", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("projectComments", "authorId",
            doc => Meteor.users.find(doc.authorId, {fields: {"username": 1, "profile.photoId": 1}}));
    this.addDependency("users", "profile.photoId", doc => Avatars.find(doc.profile.photoId));
    return ProjectComments.find(filter, generateOptions(limit, [], "createdAt", true));
});

Meteor.publish('customPage', function (slug) {
    return CustomPages.find({slug});
});

Meteor.publish(null, () => Phrases.find({}));

Meteor.publish(null, () => Meteor.roles.find({}));

Meteor.publish(null, function() {
    if (this.userId) {
        const user = Meteor.users.findOne({_id: this.userId});
        if (user && user.profile) {
            return Avatars.find(user.profile.photoId);
        }
    }
    this.ready();
});
<commit_msg>fix(server): Closed event redirect<commit_after>function debugSleep(ms) {
    if (Meteor.settings.debug) {
        Meteor._sleepForMs(ms);
    }
}

function clearFilter(inFilter) {
    inFilter = inFilter || {};
    const filter = {};
    Object.keys(inFilter).forEach((k) => {
        if (inFilter[k]) {
            filter[k] = inFilter[k]
        }
    });
    return filter;
}

function generateOptions(limit = 0, omitFields = [], sortField = "submitted", reverse = true) {
    const options = {};
    if (limit && limit > 0) {
        options.limit = limit;
    }
    if (omitFields && omitFields.length) {
        options.fields = {};
        for (let f of omitFields) {
            options.fields[f] = false;
        }
    }
    if (sortField) {
        options.sort = {};
        options.sort[sortField] = reverse ? -1 : 1;
    }
    return options;
}

Meteor.smartPublish('articles', function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("articles", "imageId", doc => Images.find(doc.imageId));
    return Articles.find(filter, generateOptions(limit, ["text"], "createdAt"));
});

Meteor.smartPublish("article", function (slug) {
    this.addDependency("articles", "imageId", doc => Images.find(doc.imageId));
    return Articles.find({slug: slug});
});

Meteor.smartPublish("tempArticle", function () {
    const userId = this.userId || "";
    if (userId && Roles.userIsInRole(userId, ['admin'])) {
        return TempArticles.find({authorId: userId});
    }
    return [];
});

Meteor.publish("tags", function () {
    return Tags.find();
});

Meteor.smartPublish('jobs', function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("jobs", "companyName", doc => Companies.find({name: doc.companyName}));
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Jobs.find(filter, generateOptions(limit, ["description"], "createdAt"));
});

Meteor.smartPublish("job", function (slug) {
    this.addDependency("jobs", "companyName", doc => Companies.find({name: doc.companyName}));
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Jobs.find({slug: slug});
});

Meteor.smartPublish("companies", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("companies", "imageId", doc =>  Images.find(doc.imageId));
    return Companies.find(filter, generateOptions(limit, ["text"]));
});

Meteor.publish("companyNames", function () {
    return Companies.find({}, {fields: {name: 1}});
});

Meteor.smartPublish("company", function (slug) {
    this.addDependency("companies", "imageId", doc => Images.find(doc.imageId));
    return Companies.find({slug: slug});
});

Meteor.publish("featuredCompanies", function () {
    return FeaturedCompanies.find({});
});

Meteor.smartPublish("projects", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    this.addDependency("projects", "listImageId", doc => doc.listImageId ? Images.find(doc.listImageId) : []);
    return Projects.find(filter, generateOptions(limit, ["description"], "createdAt", true));
});

Meteor.smartPublish("project", function (slug) {
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    if (this.userId) {
        this.addDependency("projects", "_id",
                doc => Participations.find({authorId: this.userId, projectId: doc._id}))
    }
    return Projects.find({slug: slug});
});

Meteor.publish("featuredProjects", function (limit) {
    return Projects.find({}, generateOptions(limit, ["description"], "importance", true));
});

Meteor.smartPublish("spEvents", function (limit, filter) {
    filter = clearFilter(filter);
    //filter['$or'] = [{closed: {'$exists': false}}, {closed: false}];
    return SpEvents.find(filter, generateOptions(limit, ["text", "additionalText"]));
});

Meteor.smartPublish("spEvent", function (slug) {
    const userId = this.userId || "";
    return [
        SpEvents.find({slug: slug}),
        SpEventRegistrations.find({userId: userId})
    ]
});

Meteor.smartPublish("spEventRegistrations", function (slug) {
    const userId = this.userId || "";
    if (userId && Roles.userIsInRole(userId, ['admin'])) {
        this.addDependency("spEvents", "_id", doc => SpEventRegistrations.find({eventId: doc._id}));
        this.addDependency("spEventRegistrations", "userId",
                doc => Meteor.users.find({_id: doc.userId}));
        return SpEvents.find({slug: slug});
    }
    else {
        return [];
    }
});

Meteor.smartPublish("profile", function (username) {
    this.addDependency("users", "profile.photoId", doc => Avatars.find(doc.profile.photoId));
    this.addDependency("users", "_id", doc => Participations.find({authorId: doc._id}));
    this.addDependency("participations", "projectId",
            doc => Projects.find(doc.projectId, {fields: {name: 1, slug: 1, imageId: 1}}));
    this.addDependency("projects", "imageId", doc => Images.find(doc.imageId));
    const user = Meteor.users.findOne({username: username});
    if (user.profile && user.profile.isPrivate && this.userId !== user.id) {
        return Meteor.users.find({username: username},
            {fields: {"_id": 1, "username": 1, "profile.firstName": 1, "profile.lastName": 1}});
    }
    else {
        return Meteor.users.find({username: username}, {fields: {"_id": 1, "username": 1, profile: 1}});
    }
});

Meteor.publish('countries', function () {
    return Locations.find({});
});

Meteor.publish('professions', function () {
    return Professions.find({});
});

Meteor.smartPublish("projectComments", function (limit, filter) {
    filter = clearFilter(filter);
    this.addDependency("projectComments", "authorId",
            doc => Meteor.users.find(doc.authorId, {fields: {"username": 1, "profile.photoId": 1}}));
    this.addDependency("users", "profile.photoId", doc => Avatars.find(doc.profile.photoId));
    return ProjectComments.find(filter, generateOptions(limit, [], "createdAt", true));
});

Meteor.publish('customPage', function (slug) {
    return CustomPages.find({slug});
});

Meteor.publish(null, () => Phrases.find({}));

Meteor.publish(null, () => Meteor.roles.find({}));

Meteor.publish(null, function() {
    if (this.userId) {
        const user = Meteor.users.findOne({_id: this.userId});
        if (user && user.profile) {
            return Avatars.find(user.profile.photoId);
        }
    }
    this.ready();
});
<|endoftext|>


<commit_before>/**
 * ngNavigation - v0.1.1
 *
 * Copyright (c) 2015 David Vuong <david.vuong256@gmail.com>
 * Licensed MIT
 */
!function(a){a.service("Navigation",["$rootScope","$window","$location",function(a,b,c){var d=this,e={appendSlash:!1,stripSlash:!1,rootRoute:void 0,ignoreRoutes:[]};d._endsWith=function(a,b){return-1!==a.indexOf(b,a.length-b.length)},d._overrideDefaults=function(a){if(a&&(angular.forEach(a,function(a,b){angular.isDefined(a)&&(e[b]=a)}),e.appendSlash&&e.stripSlash))throw"options.appendSlash and options.stripSlash are mutually exclusive"},d._deconstructUrlPath=function(a){for(var b,c=/\+/g,d=/([^&=]+)=?([^&]*)/g,e=function(a){return decodeURIComponent(a.replace(c," "))},f=a.split(/\?(.+)?/),g=f[0],h=f.slice(1,-1).join("&"),i={};b=d.exec(h);)i[e(b[1])]=e(b[2]);return{url:g,params:i}},d._route=function(a,b){return b?c.path(a).search(b):c.path(a)},d._routeChangeListener=function(a,b,c){if(d._isClearing)return void(d._isClearing=!1);if(!d._isRouting&&b&&a!==b){if(a===e.rootRoute)return d.clearRouteStack();a===d.peakRouteStack().url&&d._routeStack.pop(),-1===e.ignoreRoutes.indexOf(b)&&(d._isRouting=!0,d.pushToRouteStack(b,c),d._isRouting=!1)}},d._isUiRouterInstalled=function(){try{angular.module("ui.router")}catch(a){return!1}return!0},d._listenToRouteChange=function(){var b,c;d._isUiRouterInstalled()?(b="$stateChangeSuccess",c=function(a,b,c,e,f){e.name&&d._routeChangeListener(b.url,e.url,f)}):(b="$routeChangeSuccess",c=function(a,b,c){c&&d._routeChangeListener(b.originalPath,c.originalPath,c.params)}),a.$on(b,c)},d.init=function(a){this._hasInit||(d._overrideDefaults(a),d._hasInit=!0,d._isClearing=!1,d._isRouting=!1,d._routeStack=[],d._listenToRouteChange())},d.peakRouteStack=function(){return d._routeStack[d._routeStack.length-1]||{}},d.pushToRouteStack=function(a,b){if(b=b||{},a){var c=d._deconstructUrlPath(a);if(c.params&&!angular.equals(c.params,{})&&(a=c.url,b.params=c.params),b.params=b.params||{},e.appendSlash&&!d._endsWith(a,"/")&&(a+="/"),e.stripSlash&&d._endsWith(a,"/")&&(a=a.substring(0,a.length-1)),d.peakRouteStack().url!==a){var f={url:a,params:b.params,label:b.label};d._routeStack.push(f)}}},d.routeTo=function(a,b){if(!d._isRouting){b=b||{},d._isRouting=!0,b.clearStack&&d.clearRouteStack();var c=d._deconstructUrlPath(a);c.params&&!angular.equals(c.params,{})&&(a=c.url,b.params=c.params),b.params=b.params||{},d._route(a,b.params),d._isRouting=!1}},d.routeBack=function(a){a=a||{};var c=d.isBackRouteAvailable(),e=!angular.equals(a,{});return c||e?!c&&e?(d._isClearing=!0,d._route(a.url,a.params||{})):(d._routeStack.pop(),d._isClearing=!0,b.history.back()):void 0},d.isBackRouteAvailable=function(){return!!d._routeStack.length},d.clearRouteStack=function(){d._routeStack.length=0,d._isClearing=!0},d.getRouteStack=function(){return d._routeStack},d.getDefaultOptions=function(){return e}}])}(angular.module("ngNavigation",[]));<commit_msg>chore(minification): building ngNavigation<commit_after>/**
 * ngNavigation - v0.1.1
 *
 * Copyright (c) 2015 David Vuong <david.vuong256@gmail.com>
 * Licensed MIT
 */
!function(a){a.service("Navigation",["$rootScope","$window","$location",function(a,b,c){var d=this,e={appendSlash:!1,stripSlash:!1,rootRoute:void 0,ignoreRoutes:[]};d._endsWith=function(a,b){return-1!==a.indexOf(b,a.length-b.length)},d._overrideDefaults=function(a){if(a&&(angular.forEach(a,function(a,b){angular.isDefined(a)&&(e[b]=a)}),e.appendSlash&&e.stripSlash))throw"options.appendSlash and options.stripSlash are mutually exclusive"},d._deconstructUrlPath=function(a){for(var b,c=/\+/g,d=/([^&=]+)=?([^&]*)/g,e=function(a){return decodeURIComponent(a.replace(c," "))},f=a.split(/\?(.+)?/),g=f[0],h=f.slice(1,-1).join("&"),i={};b=d.exec(h);)i[e(b[1])]=e(b[2]);return{url:g,params:i}},d._route=function(a,b){return b?c.path(a).search(b):c.path(a)},d._routeChangeListener=function(a,b,c){if(d._isClearing||d._isIgnoring)return d._isClearing=!1,void(d._isIgnoring=!1);if(!d._isRouting&&b&&a!==b){if(a===e.rootRoute)return d.clearRouteStack();a===d.peakRouteStack().url&&d._routeStack.pop(),-1===e.ignoreRoutes.indexOf(b)&&(d._isRouting=!0,d.pushToRouteStack(b,c),d._isRouting=!1)}},d._isUiRouterInstalled=function(){try{angular.module("ui.router")}catch(a){return!1}return!0},d._listenToRouteChange=function(){var b,c;d._isUiRouterInstalled()?(b="$stateChangeSuccess",c=function(a,b,c,e,f){e.name&&d._routeChangeListener(b.url,e.url,f)}):(b="$routeChangeSuccess",c=function(a,b,c){c&&d._routeChangeListener(b.originalPath,c.originalPath,c.params)}),a.$on(b,c)},d.init=function(a){this._hasInit||(d._overrideDefaults(a),d._hasInit=!0,d._isClearing=!1,d._isIgnoring=!1,d._isRouting=!1,d._routeStack=[],d._listenToRouteChange())},d.peakRouteStack=function(){return d._routeStack[d._routeStack.length-1]||{}},d.pushToRouteStack=function(a,b){if(b=b||{},a){var c=d._deconstructUrlPath(a);if(c.params&&!angular.equals(c.params,{})&&(a=c.url,b.params=c.params),b.params=b.params||{},e.appendSlash&&!d._endsWith(a,"/")&&(a+="/"),e.stripSlash&&d._endsWith(a,"/")&&(a=a.substring(0,a.length-1)),d.peakRouteStack().url!==a){var f={url:a,params:b.params,label:b.label};d._routeStack.push(f)}}},d.routeTo=function(a,b){if(!d._isRouting){b=b||{},d._isRouting=!0,b.clearStack&&d.clearRouteStack(),b.ignoreBackRoute&&(d._isIgnoring=!0);var c=d._deconstructUrlPath(a);c.params&&!angular.equals(c.params,{})&&(a=c.url,b.params=c.params),b.params=b.params||{},d._route(a,b.params),d._isRouting=!1}},d.routeBack=function(a){a=a||{};var c=d.isBackRouteAvailable(),e=!angular.equals(a,{});return c||e?!c&&e?(d._isClearing=!0,d._route(a.url,a.params||{})):(d._routeStack.pop(),d._isClearing=!0,b.history.back()):void 0},d.isBackRouteAvailable=function(){return!!d._routeStack.length},d.clearRouteStack=function(){d._routeStack.length=0,d._isClearing=!0},d.getRouteStack=function(){return d._routeStack},d.getDefaultOptions=function(){return e}}])}(angular.module("ngNavigation",[]));<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * Tandem is used to assign unique identifiers to instances in PhET simulations and register/unregister them in a
 * registry. It is used to support PhET-iO.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString ); // Tandem can't depend on joist, so requiring packageJSON doesn't work
  var PHET_IO_ENABLED = !!( window.phet && window.phet.phetio );

  // used to keep track of missing tandems, see phet.phetio.queryParameters.printMissingTandems
  var missingTandems = {
    required: [],
    optional: [],
    uninstrumented: []
  };

  // Listeners that will be notified when items are registered/deregistered. See doc in addInstanceListener
  var instanceListeners = [];

  // variables
  // Before listeners are wired up, tandems are buffered.  When listeners are wired up, Tandem.launch() is called
  // and buffered tandems are flushed, then subsequent tandems are delivered to listeners directly
  var launched = false;
  var bufferedElements = [];

  /**
   * Typically, sims will create tandems using `tandem.createTandem`.  This constructor is used internally or when
   * a tandem must be created from scratch.
   *
   * @param {string} phetioID - unique identifier as a string ('' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( phetioID, options ) {

    // options (even subtype options) must be stored on the instance so they can be passed through to children
    // Note: Make sure that added options here are also added to options for inheritance and/or
    // for composition (createTandem/parentTandem) as they make sense.
    options = _.extend( {

      // if the tandem is not supplied and required, an error will be thrown.
      supplied: true,

      // required === false means it is an optional tandem
      required: true
    }, options );

    // @public (read-only)
    this.phetioID = ( phetioID !== undefined ) ? phetioID : '';

    // @private
    this.required = options.required;

    // @private
    this.supplied = options.supplied;
  }

  tandemNamespace.register( 'Tandem', Tandem );

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetioEngine.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {PhetioObject} instance - the instance to add
     * @public
     */
    addInstance: function( instance ) {

      assert && assert( arguments.length === 1, 'Tandem.addInstance takes one argument' );

      // Check that the instrumented instance is an instance of PhetioObject, cannot use typical require statement for
      // PhetioObject because it creates a module loading loop
      assert && assert( instance instanceof tandemNamespace.PhetioObject, 'Instance should be of type PhetioObject' );

      if ( PHET_IO_ENABLED ) {

        // Throw an error if the tandem is required but not supplied
        if ( Tandem.validationEnabled() ) {
          assert && assert( !( this.required && !this.supplied ), 'Tandem was required but not supplied' );
        }

        // printMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.printMissingTandems && ( this.required && !this.supplied ) ) {
          missingTandems.required.push( { phetioID: this.phetioID, stack: new Error().stack } );
        }

        // If tandem is optional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.printMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally Font is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              missingTandems.optional.push( { phetioID: this.phetioID, stack: stackTrace } );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedElements.push( instance );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( instance );
          }
        }
      }
    },

    /**
     * Removes an instance from the registry
     * @param {PhetioObject} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = ( this.phetioID.length > 0 ) ? phetio.PhetioIDUtils.append( this.phetioID, id ) : id;

      // Any child of something should be passed all inherited options. Make sure that this extend call includes all
      // that make sense from the constructor's extend call.
      options = _.extend( {
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the string passed to createGroupTandem.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     * @public
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( phetio.PhetioIDUtils.append( this.phetioID, id ) );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     * @public
     */
    get tail() { // TODO: rename to getComponentName()
      return phetio.PhetioIDUtils.getComponentName( this.phetioID );
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     * @public
     */
    get parentTandem() {
      var headID = phetio.PhetioIDUtils.getParentID( this.phetioID );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied
      } );
    }
  }, {

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     * @public
     * @static
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedElements.length > 0 ) {
        var element = bufferedElements.shift();
        element.tandem.addInstance( element );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param {Object} [options]
     * @public
     * @static
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     * @public
     * @static
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( this.validationEnabled() ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.printMissingTandems ) {
          missingTandems.uninstrumented.push( { stack: new Error().stack } );
        }
      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     * @public
     * @static
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED &&
             phet.phetio.queryParameters.phetioValidateTandems &&

             // If we are printing the missing tandems, then validation must be disabled because the intention is to
             // run with partial tandem coverage and see which are missing.
             !phet.phetio.queryParameters.printMissingTandems;
    },

    /**
     * Returns true if the bufferedElements contain the given phetioID.
     * @param {string} phetioID
     * @returns {boolean}
     * @public
     */
    containsBufferedID: function( phetioID ) {
      return bufferedElements.map( function( instance ) {return instance.tandem.phetioID;} ).indexOf( phetioID ) >= 0;
    }
  } );

  // The next few statics are created outside the static block because they instantiate Tandem instances.

  /**
   * The root tandem for a simulation
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.rootTandem = new Tandem( toCamelCase( packageJSON.name ) );

  /**
   * Many simulation elements are nested under "general".
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.generalTandem = Tandem.rootTandem.createTandem( 'general' );

  /**
   * Used to indicate a common code component that supports tandem, but doesn't not require it.
   * If a tandem is not passed through to this instance, then it will not be instrumented.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.optional = Tandem.rootTandem.createTandem( 'optionalTandem', {
    required: false,
    supplied: false
  } );

  /**
   * Some common code (such as Checkbox or RadioButton) must always be instrumented and hence requires a tandem to be
   * passed in.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.required = Tandem.rootTandem.createTandem( 'requiredTandem', {

    // let printMissingTandems bypass this
    required: PHET_IO_ENABLED && ( phet.phetio.queryParameters.phetioValidateTandems || phet.phetio.queryParameters.printMissingTandems ),
    supplied: false
  } );

  /**
   * Expose collected missing tandems only populated from specific query parameter, see printMissingTandems for more
   * @public (phet-io internal)
   * @type {Object}
   */
  Tandem.missingTandems = missingTandems;

  /**
   * Group Tandem -- Declared in the same file to avoid circular reference errors in module loading.
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    /**
     * Creates the next tandem in the group.
     * @returns {Tandem}
     * @public
     */
    createNextTandem: function() {
      return new Tandem( this.phetioID + '_' + ( this.groupElementIndex++ ) );
    }
  } );

  return Tandem;
} );<commit_msg>Rename printMissingTandems=>phetioPrintMissingTandems, see https://github.com/phetsims/tandem/issues/73<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Tandem is used to assign unique identifiers to instances in PhET simulations and register/unregister them in a
 * registry. It is used to support PhET-iO.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString ); // Tandem can't depend on joist, so requiring packageJSON doesn't work
  var PHET_IO_ENABLED = !!( window.phet && window.phet.phetio );

  // used to keep track of missing tandems, see phet.phetio.queryParameters.phetioPrintMissingTandems
  var missingTandems = {
    required: [],
    optional: [],
    uninstrumented: []
  };

  // Listeners that will be notified when items are registered/deregistered. See doc in addInstanceListener
  var instanceListeners = [];

  // variables
  // Before listeners are wired up, tandems are buffered.  When listeners are wired up, Tandem.launch() is called
  // and buffered tandems are flushed, then subsequent tandems are delivered to listeners directly
  var launched = false;
  var bufferedElements = [];

  /**
   * Typically, sims will create tandems using `tandem.createTandem`.  This constructor is used internally or when
   * a tandem must be created from scratch.
   *
   * @param {string} phetioID - unique identifier as a string ('' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( phetioID, options ) {

    // options (even subtype options) must be stored on the instance so they can be passed through to children
    // Note: Make sure that added options here are also added to options for inheritance and/or
    // for composition (createTandem/parentTandem) as they make sense.
    options = _.extend( {

      // if the tandem is not supplied and required, an error will be thrown.
      supplied: true,

      // required === false means it is an optional tandem
      required: true
    }, options );

    // @public (read-only)
    this.phetioID = ( phetioID !== undefined ) ? phetioID : '';

    // @private
    this.required = options.required;

    // @private
    this.supplied = options.supplied;
  }

  tandemNamespace.register( 'Tandem', Tandem );

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetioEngine.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {PhetioObject} instance - the instance to add
     * @public
     */
    addInstance: function( instance ) {

      assert && assert( arguments.length === 1, 'Tandem.addInstance takes one argument' );

      // Check that the instrumented instance is an instance of PhetioObject, cannot use typical require statement for
      // PhetioObject because it creates a module loading loop
      assert && assert( instance instanceof tandemNamespace.PhetioObject, 'Instance should be of type PhetioObject' );

      if ( PHET_IO_ENABLED ) {

        // Throw an error if the tandem is required but not supplied
        if ( Tandem.validationEnabled() ) {
          assert && assert( !( this.required && !this.supplied ), 'Tandem was required but not supplied' );
        }

        // phetioPrintMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.phetioPrintMissingTandems && ( this.required && !this.supplied ) ) {
          missingTandems.required.push( { phetioID: this.phetioID, stack: new Error().stack } );
        }

        // If tandem is optional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.phetioPrintMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally Font is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              missingTandems.optional.push( { phetioID: this.phetioID, stack: stackTrace } );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedElements.push( instance );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( instance );
          }
        }
      }
    },

    /**
     * Removes an instance from the registry
     * @param {PhetioObject} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = ( this.phetioID.length > 0 ) ? phetio.PhetioIDUtils.append( this.phetioID, id ) : id;

      // Any child of something should be passed all inherited options. Make sure that this extend call includes all
      // that make sense from the constructor's extend call.
      options = _.extend( {
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the string passed to createGroupTandem.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     * @public
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( phetio.PhetioIDUtils.append( this.phetioID, id ) );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     * @public
     */
    get tail() { // TODO: rename to getComponentName()
      return phetio.PhetioIDUtils.getComponentName( this.phetioID );
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     * @public
     */
    get parentTandem() {
      var headID = phetio.PhetioIDUtils.getParentID( this.phetioID );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied
      } );
    }
  }, {

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     * @public
     * @static
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedElements.length > 0 ) {
        var element = bufferedElements.shift();
        element.tandem.addInstance( element );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param {Object} [options]
     * @public
     * @static
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     * @public
     * @static
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( this.validationEnabled() ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.phetioPrintMissingTandems ) {
          missingTandems.uninstrumented.push( { stack: new Error().stack } );
        }
      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     * @public
     * @static
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED &&
             phet.phetio.queryParameters.phetioValidateTandems &&

             // If we are printing the missing tandems, then validation must be disabled because the intention is to
             // run with partial tandem coverage and see which are missing.
             !phet.phetio.queryParameters.phetioPrintMissingTandems;
    },

    /**
     * Returns true if the bufferedElements contain the given phetioID.
     * @param {string} phetioID
     * @returns {boolean}
     * @public
     */
    containsBufferedID: function( phetioID ) {
      return bufferedElements.map( function( instance ) {return instance.tandem.phetioID;} ).indexOf( phetioID ) >= 0;
    }
  } );

  // The next few statics are created outside the static block because they instantiate Tandem instances.

  /**
   * The root tandem for a simulation
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.rootTandem = new Tandem( toCamelCase( packageJSON.name ) );

  /**
   * Many simulation elements are nested under "general".
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.generalTandem = Tandem.rootTandem.createTandem( 'general' );

  /**
   * Used to indicate a common code component that supports tandem, but doesn't not require it.
   * If a tandem is not passed through to this instance, then it will not be instrumented.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.optional = Tandem.rootTandem.createTandem( 'optionalTandem', {
    required: false,
    supplied: false
  } );

  /**
   * Some common code (such as Checkbox or RadioButton) must always be instrumented and hence requires a tandem to be
   * passed in.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.required = Tandem.rootTandem.createTandem( 'requiredTandem', {

    // let phetioPrintMissingTandems bypass this
    required: PHET_IO_ENABLED && ( phet.phetio.queryParameters.phetioValidateTandems || phet.phetio.queryParameters.phetioPrintMissingTandems ),
    supplied: false
  } );

  /**
   * Expose collected missing tandems only populated from specific query parameter, see phetioPrintMissingTandems for more
   * @public (phet-io internal)
   * @type {Object}
   */
  Tandem.missingTandems = missingTandems;

  /**
   * Group Tandem -- Declared in the same file to avoid circular reference errors in module loading.
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    /**
     * Creates the next tandem in the group.
     * @returns {Tandem}
     * @public
     */
    createNextTandem: function() {
      return new Tandem( this.phetioID + '_' + ( this.groupElementIndex++ ) );
    }
  } );

  return Tandem;
} );<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Tandem is a general instance registry that can be used to track creation/disposal of instances in
 * PhET Simulations.  It is used for together.js instrumentation.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   */
  function Tandem( id ) {

    // @private
    this.id = id;
  }

  var instanceListeners = [];

  // Export so preloads such as together can use it.
  window.Tandem = Tandem;

  Tandem = inherit( Object, Tandem, {
    addInstance: function( instance ) {
      for ( var i = 0; i < instanceListeners.length; i++ ) {
        instanceListeners[ i ].addInstance( this.id, instance );
      }
    },
    removeInstance: function( instance ) {
      for ( var i = 0; i < instanceListeners.length; i++ ) {
        instanceListeners[ i ].removeInstance( this.id, instance );
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @returns {Tandem}
     */
    createTandem: function( id ) {
      if ( this.id.length > 0 ) {
        return new Tandem( this.id + '.' + id );
      }
      else {
        return new Tandem( id );
      }
    }
  }, {
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    }
  } );

  // Check for listeners in the preload.  This is necessary so that together.js can
  // receive notifications about items created during static initialization such as Solute.js
  // which is created before Sim.js runs.
  if ( window.tandemPreloadInstanceListeners ) {
    for ( var i = 0; i < window.tandemPreloadInstanceListeners.length; i++ ) {
      Tandem.addInstanceListener( window.tandemPreloadInstanceListeners[ i ] );
    }
  }

  return Tandem;
} );<commit_msg>Added support for no-arg (top level) tandem<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Tandem is a general instance registry that can be used to track creation/disposal of instances in
 * PhET Simulations.  It is used for together.js instrumentation.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   */
  function Tandem( id ) {

    if (arguments.length===0){
      id= '';
    }
    // @private
    this.id = id;
  }

  var instanceListeners = [];

  // Export so preloads such as together can use it.
  window.Tandem = Tandem;

  Tandem = inherit( Object, Tandem, {
    addInstance: function( instance ) {
      for ( var i = 0; i < instanceListeners.length; i++ ) {
        instanceListeners[ i ].addInstance( this.id, instance );
      }
    },
    removeInstance: function( instance ) {
      for ( var i = 0; i < instanceListeners.length; i++ ) {
        instanceListeners[ i ].removeInstance( this.id, instance );
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @returns {Tandem}
     */
    createTandem: function( id ) {
      if ( this.id.length > 0 ) {
        return new Tandem( this.id + '.' + id );
      }
      else {
        return new Tandem( id );
      }
    }
  }, {
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    }
  } );

  // Check for listeners in the preload.  This is necessary so that together.js can
  // receive notifications about items created during static initialization such as Solute.js
  // which is created before Sim.js runs.
  if ( window.tandemPreloadInstanceListeners ) {
    for ( var i = 0; i < window.tandemPreloadInstanceListeners.length; i++ ) {
      Tandem.addInstanceListener( window.tandemPreloadInstanceListeners[ i ] );
    }
  }

  return Tandem;
} );<|endoftext|>


<commit_before>if (enyo && enyo.version) {
	enyo.version.canvas = "2.3.0-pre.11";
}
<commit_msg>Update version to 2.3.0-pre.12<commit_after>if (enyo && enyo.version) {
	enyo.version.canvas = "2.3.0-pre.12";
}
<|endoftext|>


<commit_before>var _ = require('underscore'),
    util = require('../lib/util'),
    ForumPost = require('../models/forum').ForumPost,
    ForumReply = require('../models/forum').ForumReply,
    ForumComment = require('../models/forum').ForumComment;

var matchObjectId = /^[0-9a-fA-F]{24}$/;
var isObjectId = function(string){
    return matchObjectId.test(string);
};

module.exports.index = function (req, res, next) {
    // sende med prosjekt i url, eller søke opp prosjekter for alle tags?
    // sende med prosjekt i url
    var tagquery,
        tags;

    if (req.params[0]) {
        tags = req.params[0].split("/");
        tagquery = {'tags': { $all: tags }};
    } else {
        tagquery = {};
    }
    ForumPost.find(tagquery)
    .sort('-created')
    .populate('creator', 'username name')
    .select('_id title created mdtext tags permissions creator')
    .exec(function (err, posts) {
        if (err) {
            return next(err);
        }

        // TODO: have nicer ids on posts?
        posts = _.map(posts, function(post){
            var p = post.toJSON();
            p.oid = util.h2b64(post.id);
            return p;
        });

        res.format({
            json: function () {
                res.json(200, posts);
            },
            html: function () {
                res.render('forum/index', {
                    posts: posts
                });
            }
        });
    });
};

module.exports.create_post = function (req, res, next) {
    var post = new ForumPost();
    post.title = req.body.title;
    post.creator = req.user;
    post.mdtext = req.body.mdtext;
    post.permissions = util.set_permissions(req.body.permissions);
    post.save(function (err) {
        if (err) {
            return next(err);
        }
        post.populate('creator', function (err, post) {
            res.json(200, post);
        });
    });
};

module.exports.delete_post = function (req, res, next) {
    var id = req.params.id;

    ForumPost.findByIdAndRemove(id, function (err, post) {
        if (err) { return next(err); }
        res.json(200, post);
    });
};

module.exports.get_post = function (req, res, next) {
    req.params.id = util.b642h(req.params.id);

    // if given id is not a valid ObjectID, return 404.
    if (!isObjectId(req.params.id)){
        return next();
    }

    ForumPost.findById(req.params.id).populate('creator').exec(function (err, post) {
        if (err) {
            return next(err);
        }

        post.replies.reverse();

        res.format({
            json: function(){
                res.json(200, post);
            },

            html: function(){
                res.render('forum/thread', {
                    post: post
                });
            }
        });
    });
};

module.exports.create_reply = function (req, res, next) {
    var postid = req.params.postid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        var reply = new ForumReply();
        reply.mdtext = req.body.mdtext;
        reply.creator = req.user;

        post.replies.push(reply);
        post.save(function (err) {
            if (err) {
            return next(err);
            }
            res.json(200, reply);
        });
    });
};

module.exports.delete_reply = function (req, res, next) {
    var postid = req.params.postid,
        replyid = req.params.replyid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        post.replies.pull(replyid);
        post.save(function (err) {
            if (err) {
                return next(err);
            }
            res.json(200);
        });
    });
};

module.exports.get_replies = function (req, res, next) {
    ForumPost.findById(req.params.id, function (err, post) {
        if (err) {
            return next(err);
        }
        res.json(200, post.replies);
    });
};

module.exports.create_comment = function (req, res, next) {
    var replyid = req.params.replyid;

    ForumPost.findOne({'replies._id': replyid}, function (err, post) {
        if (err) {
            return next(err);
        }
        if (post) {
            var comment = new ForumComment();
            comment.mdtext = req.body.mdtext;
            comment.creator = req.user;
            var reply = post.replies.id(replyid);
            if (reply === undefined) {
                return next(new Error('Reply not found, could not add comment'));
            }
            reply.comments.push(comment);
            post.save(function (err) {
                if (err) {
                    return next(err);
                }
                res.json(200, comment);
            });
        } else {
            return next(new Error('Post not found, could not add comment'));
        }
    });
};

module.exports.delete_comment = function (req, res, next) {
    var postid = req.params.postid,
        replyid = req.params.replyid,
        commentid = req.params.commentid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        if (post) {
            var reply = post.replies.id(replyid);
            if (reply === undefined) {
                return next(new Error('Reply not found, could not add comment'));
            }
            reply.comments.pull(commentid);
            post.save(function (err) {
                if (err) {
                    return next(err);
                }
                res.json(200);
            });
        } else {
            return next(new Error('Post not found, could not delete comment'));
        }
    });
};
<commit_msg>Pagination in forum backend, hard coded to 2 per page<commit_after>var _ = require('underscore'),
    util = require('../lib/util'),
    ForumPost = require('../models/forum').ForumPost,
    ForumReply = require('../models/forum').ForumReply,
    ForumComment = require('../models/forum').ForumComment;

var matchObjectId = /^[0-9a-fA-F]{24}$/;
var isObjectId = function(string){
    return matchObjectId.test(string);
};

module.exports.index = function (req, res, next) {
    // sende med prosjekt i url, eller søke opp prosjekter for alle tags?
    // sende med prosjekt i url
    var tagquery,
        tags;

    if (req.params[0]) {
        tags = req.params[0].split("/");
        tagquery = {'tags': { $all: tags }};
    } else {
        tagquery = {};
    }
    var query = ForumPost.find(tagquery)
    .sort('-created')
    .populate('creator', 'username name')
    .select('_id title created mdtext tags permissions creator');

    if (req.query.page) {
        query = query.skip(2 * req.query.page);
    }
    query = query.limit(2);
    query.exec(function (err, posts) {
        if (err) {
            return next(err);
        }

        // TODO: have nicer ids on posts?
        posts = _.map(posts, function(post){
            var p = post.toJSON();
            p.oid = util.h2b64(post.id);
            return p;
        });

        res.format({
            json: function () {
                res.json(200, posts);
            },
            html: function () {
                res.render('forum/index', {
                    posts: posts
                });
            }
        });
    });
};

module.exports.create_post = function (req, res, next) {
    var post = new ForumPost();
    post.title = req.body.title;
    post.creator = req.user;
    post.mdtext = req.body.mdtext;
    post.permissions = util.set_permissions(req.body.permissions);
    post.save(function (err) {
        if (err) {
            return next(err);
        }
        post.populate('creator', function (err, post) {
            res.json(200, post);
        });
    });
};

module.exports.delete_post = function (req, res, next) {
    var id = req.params.id;

    ForumPost.findByIdAndRemove(id, function (err, post) {
        if (err) { return next(err); }
        res.json(200, post);
    });
};

module.exports.get_post = function (req, res, next) {
    req.params.id = util.b642h(req.params.id);

    // if given id is not a valid ObjectID, return 404.
    if (!isObjectId(req.params.id)){
        return next();
    }

    ForumPost.findById(req.params.id).populate('creator').exec(function (err, post) {
        if (err) {
            return next(err);
        }

        post.replies.reverse();

        res.format({
            json: function(){
                res.json(200, post);
            },

            html: function(){
                res.render('forum/thread', {
                    post: post
                });
            }
        });
    });
};

module.exports.create_reply = function (req, res, next) {
    var postid = req.params.postid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        var reply = new ForumReply();
        reply.mdtext = req.body.mdtext;
        reply.creator = req.user;

        post.replies.push(reply);
        post.save(function (err) {
            if (err) {
            return next(err);
            }
            res.json(200, reply);
        });
    });
};

module.exports.delete_reply = function (req, res, next) {
    var postid = req.params.postid,
        replyid = req.params.replyid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        post.replies.pull(replyid);
        post.save(function (err) {
            if (err) {
                return next(err);
            }
            res.json(200);
        });
    });
};

module.exports.get_replies = function (req, res, next) {
    ForumPost.findById(req.params.id, function (err, post) {
        if (err) {
            return next(err);
        }
        res.json(200, post.replies);
    });
};

module.exports.create_comment = function (req, res, next) {
    var replyid = req.params.replyid;

    ForumPost.findOne({'replies._id': replyid}, function (err, post) {
        if (err) {
            return next(err);
        }
        if (post) {
            var comment = new ForumComment();
            comment.mdtext = req.body.mdtext;
            comment.creator = req.user;
            var reply = post.replies.id(replyid);
            if (reply === undefined) {
                return next(new Error('Reply not found, could not add comment'));
            }
            reply.comments.push(comment);
            post.save(function (err) {
                if (err) {
                    return next(err);
                }
                res.json(200, comment);
            });
        } else {
            return next(new Error('Post not found, could not add comment'));
        }
    });
};

module.exports.delete_comment = function (req, res, next) {
    var postid = req.params.postid,
        replyid = req.params.replyid,
        commentid = req.params.commentid;

    ForumPost.findById(postid, function (err, post) {
        if (err) {
            return next(err);
        }
        if (post) {
            var reply = post.replies.id(replyid);
            if (reply === undefined) {
                return next(new Error('Reply not found, could not add comment'));
            }
            reply.comments.pull(commentid);
            post.save(function (err) {
                if (err) {
                    return next(err);
                }
                res.json(200);
            });
        } else {
            return next(new Error('Post not found, could not delete comment'));
        }
    });
};
<|endoftext|>


<commit_before>/*global define, module*/

(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(factory);
	} else if (typeof exports === 'object') {
		// Node. Does not work with strict CommonJS, but
		// only CommonJS-like enviroments that support module.exports,
		// like Node.
		module.exports = factory();
	} else {
		// Browser globals (root is window)
		root.gtfsx = factory();
	}
}(this, function () {

	/** Converts a number representing a date returned from GTFS-Exchange into a Date object.
	 * @returns {Date}
	 */
	function convertDateToDateObject(/*{number}*/ n) {
		return new Date(n * 1000);
	}

	function Agency(data) {
		this.dataexchange_id = data.dataexchange_id; // "abq-ride"
		this.feed_baseurl = data.feed_baseurl; // "http://data.cabq.gov/transit/gtfs/google_transit.zip",
		this.name = data.name; // "ABQ Ride",
		this.area = data.area; // "Albuquerque",
		this.url = data.url; // "http://myabqride.com",
		this.country = data.country; // "United States",
		this.state = data.state; // "New Mexico",
		this.license_url = data.license_url; // "",
		this.dataexchange_url = data.dataexchange_url; // "http://www.gtfs-data-exchange.com/agency/abq-ride/",
		this.date_added = convertDateToDateObject(data.date_added); // 1340739867.0,
		this.date_last_updated = convertDateToDateObject(data.date_last_updated); // 1346727786.0,
		this.is_official = data.is_official; // true,
	}

	function Datafile(data) {
		this.description = data.description; // "Archived from http://data.cabq.gov/transit/gtfs/google_transit.zip",
		this.md5sum = data.md5sum; // "f96e9fa37f13789e3d98f09b599e9c4a",
		this.file_url = data.file_url; // "http://gtfs.s3.amazonaws.com/abq-ride_20120904_0303.zip",
		this.agencies = data.agencies; // ["abq-ride"],
		this.filename = data.filename; // "abq-ride_20120904_0303.zip",
		this.date_added = convertDateToDateObject(data.date_added); // 1346727786.0,
		this.uploaded_by_user = data.uploaded_by_user; // "abq-ride-archiver",
		this.size = data.size; // 3094785
	}

	/** For use with JSON.parse(). Dates numbers will be converted to Date objects.
	 * @param {string} k - The property name.
	 * @param {?(number|string|boolean|Array|Object)} v - The value of the property.
	 * @returns {?(number|string|boolean|Array|Object|Date)}
	 */
	function agencyReviver(k, v) {
		var output = v;
		if (v.hasOwnProperty("is_official")) {
			output = Agency(v);
		}
		return output;
	}

	/** Parses a JSON string into an object.
	 */
	function parseAgencyResponse(/**{String}*/ json) {
		return JSON.parse(json, agencyReviver);
	}

	// Just return a value to define the module export.
	// This example returns an object, but the module
	// can return a function as the exported value.
	return {
		Agency: Agency,
		parseAgencyResponse: parseAgencyResponse
	};
}));<commit_msg>Added jsdoc comments.<commit_after>/*global define, module*/

(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(factory);
	} else if (typeof exports === 'object') {
		// Node. Does not work with strict CommonJS, but
		// only CommonJS-like enviroments that support module.exports,
		// like Node.
		module.exports = factory();
	} else {
		// Browser globals (root is window)
		root.gtfsx = factory();
	}
}(this, function () {

	/** Converts a number representing a date returned from GTFS-Exchange into a Date object.
	 * @returns {Date}
	 */
	function convertDateToDateObject(/*{number}*/ n) {
		return new Date(n * 1000);
	}

	/** Represents an element of the datafile array returned from the API endpoint http://www.gtfs-data-exchange.com/api/agency?agency={dataexchange_id}.
	 * @param {Object} data
	*/
	function Datafile(data) {
		/** @member {string} */
		this.description = data.description; // "Archived from http://data.cabq.gov/transit/gtfs/google_transit.zip",
		/** @member {string} */
		this.md5sum = data.md5sum; // "f96e9fa37f13789e3d98f09b599e9c4a",
		/** @member {string} */
		this.file_url = data.file_url; // "http://gtfs.s3.amazonaws.com/abq-ride_20120904_0303.zip",
		/** @member {string} */
		this.agencies = data.agencies; // ["abq-ride"],
		/** @member {string} */
		this.filename = data.filename; // "abq-ride_20120904_0303.zip",
		/** @member {Date} */
		this.date_added = convertDateToDateObject(data.date_added); // 1346727786.0,
		/** @member {string} */
		this.uploaded_by_user = data.uploaded_by_user; // "abq-ride-archiver",
		/** @member {number} */
		this.size = data.size; // 3094785
	}

	/** An object representing an agency that publishes GTFS data to GTFS-Exchange.
	 * @param {Object} data
	 * @param {?Object.<string, object>} datafiles
	 */
	function Agency(data, datafiles) {
		/** @member {string} */
		this.dataexchange_id = data.dataexchange_id; // "abq-ride"
		/** @member {string} */
		this.feed_baseurl = data.feed_baseurl; // "http://data.cabq.gov/transit/gtfs/google_transit.zip",
		/** @member {string} */
		this.name = data.name; // "ABQ Ride",
		/** @member {string} */
		this.area = data.area; // "Albuquerque",
		/** @member {string} */
		this.url = data.url; // "http://myabqride.com",
		/** @member {string} */
		this.country = data.country; // "United States",
		/** @member {string} */
		this.state = data.state; // "New Mexico",
		/** @member {string} */
		this.license_url = data.license_url; // "",
		/** @member {string} */
		this.dataexchange_url = data.dataexchange_url; // "http://www.gtfs-data-exchange.com/agency/abq-ride/",
		/** @member {Date} */
		this.date_added = convertDateToDateObject(data.date_added); // 1340739867.0,
		/** @member {Date} */
		this.date_last_updated = convertDateToDateObject(data.date_last_updated); // 1346727786.0,
		/** @member {boolean} */
		this.is_official = data.is_official; // true,
		/** @member {DataFile[]} */
		this.datafiles = datafiles || null;

		/** @member {string} latestFeedUrl - URL for the most current GTFS ZIP file */
		this.latestFeedUrl = this.dataexchange_url ? this.dataexchange_url.replace(/\/$/, "") + "/latest.zip" : null;
	}

	/** For use with JSON.parse(). Dates numbers will be converted to Date objects.
	 * @param {string} k - The property name.
	 * @param {?(number|string|boolean|Array|Object)} v - The value of the property.
	 * @returns {?(number|string|boolean|Array|Object|Date)}
	 */
	function agencyReviver(k, v) {
		var output = v;
		/*jshint eqnull:true*/
		// Detect an Agency.
		if (v.is_official != null) {
			output = new Agency(v);
		}
		/*jshint eqnull:false*/

		return output;
	}

	/** Parses a JSON string into an object.
	 */
	function parseAgencyResponse(/**{String}*/ json) {
		return JSON.parse(json, agencyReviver);
	}

	// Just return a value to define the module export.
	// This example returns an object, but the module
	// can return a function as the exported value.
	return {
		Agency: Agency,
		Datafile: Datafile,
		parseAgencyResponse: parseAgencyResponse
	};
}));<|endoftext|>


<commit_before>
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        var min = parseFloat( $('#min').val(), 10 );
        var max = parseFloat( $('#max').val(), 10 );
        var age = parseFloat( data[parseInt($("#filterChoice").val())] ) || 0; // Get column number based on values in the pre-table
	if($("#invertChoice").val() == "true"){
       		if ( ( isNaN( min ) && isNaN( max ) ) ||
       		     ( isNaN( min ) && age <= max ) ||
       		     ( min <= age   && isNaN( max ) ) ||
       		     ( min <= age   && age <= max ) )
       		{
       		    return false;
       		}
       		return true;

	}else{
       		if ( ( isNaN( min ) && isNaN( max ) ) ||
       		     ( isNaN( min ) && age <= max ) ||
       		     ( min <= age   && isNaN( max ) ) ||
       		     ( min <= age   && age <= max ) )
       		{
       		    return true;
       		}
       		return false;
	}
    }
);

function getQueryVar(variable){
       var query = window.location.search.substring(1);
       var vars = query.split("&");
       for (var i=0;i<vars.length;i++) {
               var pair = vars[i].split("=");
               if(pair[0] == variable){return pair[1];}
       }
       return(false);
}

function updateSelections(){
	var spec= $(".speciesSelect").val();
	req = "load_compare_options.php?spec=" + spec;
	$.get(req, function(data) {
		$("#compareSpecSel").empty()
		.html(data);
	});
}

$(document).ready(function() {
	updateSelections();
    	var table;
	$("#MultiGeneQueryExpression").hide();
	$(".speciesSelect").change(function () {
		updateSelections();
	});
	if (getQueryVar("netlink")){
		req = "php/gene_plasticity_query.php?";
       		var query = window.location.search.substring(1);
       		var vars = query.split("&");
		var first = true;
		var cont = 0
		var spec;
		var genes = [];
       		for (var i = 0;i < vars.length;i++) {
               		var pair = vars[i].split("=");
			if(i != 0){
				req+="&";
			}
			if(pair[0].charAt(0) == "g"){
				genes.push(pair[1]);
				if(i != 0){
					req+="&";
				}
				req+=("g" + cont + "=" + pair[1]);
				cont++;
				if (first){
					$('#multiGeneInputArea').val($('#multiGeneInputArea').val() + pair[1])
					first = false;
				}else{
					$('#multiGeneInputArea').val($('#multiGeneInputArea').val() + '\n' + pair[1])
				}
       			}
		}
	}

	$("#MultiGeneQueryExpression").click(function() {
		var genes = $("#geneSelections input:checkbox:checked").map(function(){
      			return $(this).val();
    		}).get(); // <----
    		console.log(genes);
		req = "expression_query.php?exlink=true";
		if (!genes.length > 0){
			return false;
		}
		//Build the GET request by looping through the inputs
		for(i = 0;i < genes.length;i++){
			req+="&";
			req+=("g" + i + "="+genes[i]);
		}
		req+=("&spec=" + $(".speciesSelect").val());
		window.location.href = req;
	});

	//Handles the filtering
	$('*').keyup( function() {
        	table.draw();
    		//addPopups();
    	} );
	//Handles readding in popups whenever the table is adjusted
	$(document).click(function() {
    		//addPopups();
  	});

	//Handle the multi-gene query
	$('#plasticityQueryForm').submit(function(e) {
		//Prevents the webpage from directing to the GET url
		e.preventDefault();
		var $inputs = $('#plasticityQueryForm :input');
		var vals = {};

		ind = 0;
		$inputs.each(function() {
			vals[ind] = $(this).val();
			ind++;
		});

		var lines = $('#multiGeneInputArea').val().split(/\n/);
		var texts = [];

		for (var i=0; i < lines.length; i++) {
  			// only push this line if it contains a non whitespace character.
 			 if (/\S/.test(lines[i])) {
  				texts.push($.trim(lines[i]));
  			 }
           	}
		console.log(texts);
		console.log(vals);
		var spec;
		var genes = [];
		req = "php/gene_plasticity_query.php?";
		//Build the GET request by looping through the inputs
		for(i = 0;i < texts.length;i++){
			if(i !=  0){
				req+="&";
			}
			req+=("g" + i + "="+texts[i]);
			genes.push(texts[i]);
		}
		if (document.getElementById('ANDButton').checked){
			req+=("&type=" + "AND");
		}else{
			req+=("&type=" + "OR");
		}
		//Append on the species DB to access
		req += "&orig=" + $(".speciesSelect").val();
		req += "&target=" + $("#compareSelect").val();
		req += "&comp=" + $("#compareSelect option:selected").attr("prefix");
		spec = vals[2];
		console.log(req);
		$.get(req, function(data) {
			$('#qTable').empty()
			.html(data)
			.ready(function(){
				$("#multiGeneForm").hide();
				$("#goBack").show();
				if($('#basicQueryTable tr').length > 9){
					$('#lower-rect').removeAttr('style');
				}else{
					$("#goBack").css("height","136px");
				}
				if(data == "Invalid gene used, please try again"){
					return 0;
				}else{
    				table = $('#basicQueryTable').DataTable({
					"scrollX": true
				});
				addPopups();
				addMetricPopups();
				$("#MultiGeneQueryExpression").show();
				$('#basicQueryTable').on( 'draw.dt', debounce(addPopups, 100));
				$('#basicQueryTable').on( 'draw.dt', debounce(addMetricPopups, 100));
				table.draw();
				}
			});
			table.draw();
		});
	});

});
<commit_msg>Minor fix to plasticity queries<commit_after>
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        var min = parseFloat( $('#min').val(), 10 );
        var max = parseFloat( $('#max').val(), 10 );
        var age = parseFloat( data[parseInt($("#filterChoice").val())] ) || 0; // Get column number based on values in the pre-table
	if($("#invertChoice").val() == "true"){
       		if ( ( isNaN( min ) && isNaN( max ) ) ||
       		     ( isNaN( min ) && age <= max ) ||
       		     ( min <= age   && isNaN( max ) ) ||
       		     ( min <= age   && age <= max ) )
       		{
       		    return false;
       		}
       		return true;

	}else{
       		if ( ( isNaN( min ) && isNaN( max ) ) ||
       		     ( isNaN( min ) && age <= max ) ||
       		     ( min <= age   && isNaN( max ) ) ||
       		     ( min <= age   && age <= max ) )
       		{
       		    return true;
       		}
       		return false;
	}
    }
);

function getQueryVar(variable){
       var query = window.location.search.substring(1);
       var vars = query.split("&");
       for (var i=0;i<vars.length;i++) {
               var pair = vars[i].split("=");
               if(pair[0] == variable){return pair[1];}
       }
       return(false);
}

function updateSelections(){
	var spec= $(".speciesSelect").val();
	req = "load_compare_options.php?spec=" + spec;
	$.get(req, function(data) {
		$("#compareSpecSel").empty()
		.html(data);
	});
}

$(document).ready(function() {
	updateSelections();
    	var table;
	$("#MultiGeneQueryExpression").hide();
	$(".speciesSelect").change(function () {
		updateSelections();
	});
	if (getQueryVar("netlink")){
		req = "php/gene_plasticity_query.php?";
       		var query = window.location.search.substring(1);
       		var vars = query.split("&");
		var first = true;
		var cont = 0
		var spec;
		var genes = [];
       		for (var i = 0;i < vars.length;i++) {
               		var pair = vars[i].split("=");
			if(i != 0){
				req+="&";
			}
			if(pair[0].charAt(0) == "g"){
				genes.push(pair[1]);
				if(i != 0){
					req+="&";
				}
				req+=("g" + cont + "=" + pair[1]);
				cont++;
				if (first){
					$('#multiGeneInputArea').val($('#multiGeneInputArea').val() + pair[1])
					first = false;
				}else{
					$('#multiGeneInputArea').val($('#multiGeneInputArea').val() + '\n' + pair[1])
				}
       			}
		}
	}

	$("#MultiGeneQueryExpression").click(function() {
		var genes = $("#geneSelections input:checkbox:checked").map(function(){
      			return $(this).val();
    		}).get(); // <----
    		console.log(genes);
		req = "expression_query.php?exlink=true";
		if (!genes.length > 0){
			return false;
		}
		//Build the GET request by looping through the inputs
		for(i = 0;i < genes.length;i++){
			req+="&";
			req+=("g" + i + "="+genes[i]);
		}
		req+=("&spec=" + $(".speciesSelect").val());
		window.location.href = req;
	});

	//Handles the filtering
	$('*').keyup( function() {
        	table.draw();
    		//addPopups();
    	} );
	//Handles readding in popups whenever the table is adjusted
	$(document).click(function() {
    		//addPopups();
  	});

	//Handle the multi-gene query
	$('#plasticityQueryForm').submit(function(e) {
		//Prevents the webpage from directing to the GET url
		e.preventDefault();
		var $inputs = $('#plasticityQueryForm :input');
		var vals = {};

		ind = 0;
		$inputs.each(function() {
			vals[ind] = $(this).val();
			ind++;
		});

		var lines = $('#multiGeneInputArea').val().split(/\n/);
		var texts = [];

		for (var i=0; i < lines.length; i++) {
  			// only push this line if it contains a non whitespace character.
 			 if (/\S/.test(lines[i])) {
  				texts.push($.trim(lines[i]));
  			 }
           	}
		console.log(texts);
		console.log(vals);
		var spec;
		var genes = [];
		req = "php/gene_plasticity_query.php?";
		//Build the GET request by looping through the inputs
		for(i = 0;i < texts.length;i++){
			if(i !=  0){
				req+="&";
			}
			req+=("g" + i + "="+texts[i]);
			genes.push(texts[i]);
		}
		//Append on the species DB to access
		req += "&orig=" + $(".speciesSelect").val();
		req += "&target=" + $("#compareSelect").val();
		req += "&comp=" + $("#compareSelect option:selected").attr("prefix");
		spec = vals[2];
		console.log(req);
		$.get(req, function(data) {
			$('#qTable').empty()
			.html(data)
			.ready(function(){
				$("#multiGeneForm").hide();
				$("#goBack").show();
				if($('#basicQueryTable tr').length > 9){
					$('#lower-rect').removeAttr('style');
				}else{
					$("#goBack").css("height","136px");
				}
				if(data == "Invalid gene used, please try again"){
					return 0;
				}else{
    				table = $('#basicQueryTable').DataTable({
					"scrollX": true
				});
				addPopups();
				addMetricPopups();
				$("#MultiGeneQueryExpression").show();
				$('#basicQueryTable').on( 'draw.dt', debounce(addPopups, 100));
				$('#basicQueryTable').on( 'draw.dt', debounce(addMetricPopups, 100));
				table.draw();
				}
			});
			table.draw();
		});
	});

});
<|endoftext|>