<commit_before>//setup Dependencies
var express  = require('express'),
bodyParser   = require('body-parser'),
cookieParser = require('cookie-parser'),
session      = require('express-session'),
state        = require('express-state'),
hbs          = require('./lib/exphbs'),
routes       = require('./routes'),
middleware   = require('./middleware'),
config       = require('./config'),
app          = express(),
port         = (process.env.PORT || 8000),
server       = app.listen(port, 'localhost'),
router;

//Setup Express App
state.extend(app);
app.engine(hbs.extname, hbs.engine);
app.set('view engine', hbs.extname);
app.enable('view cache');

//Uncomment this if you want strict routing (ie: /foo will not resolve to /foo/)
//app.enable('strict routing');

//Change "App" to whatever your application's name is, or leave it like this.
app.set('state namespace', 'App');

//Create an empty Data object and expose it to the client. This
//will be available on the client under App.Data.
//This is just an example, so feel free to remove this.
app.expose({}, 'Data');

if (app.get('env') === 'development') {
    app.use(middleware.logger('tiny'));
}

// Set default views directory.
app.set('views', config.dirs.views);

router = express.Router({
    caseSensitive: app.get('case sensitive routing'),
    strict       : app.get('strict routing')
});

// Parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// Parse application/json
app.use(bodyParser.json())

// Parse cookies.
app.use(cookieParser());

// Session Handling
app.use(session({secret: 'keyboard cat', resave: true, saveUninitialized: true}));

// Specify the public directory.
app.use(express.static(config.dirs.pub));

// Uncomment this line if you are using Bower, and have a bower_components directory.
// Before uncommenting this line, go into config/index.js and add config.dirs.bower there.
//app.use(express.static(config.dirs.bower));

// Use the router.
app.use(router);

///////////////////////////////////////////
//              Routes                   //
///////////////////////////////////////////

/////// ADD ALL YOUR ROUTES HERE  /////////

// The exposeTemplates() method makes the Handlebars templates that are inside /shared/templates/
// available to the client.
router.get('/', [ middleware.exposeTemplates(), routes.render('home') ]);

// A Route for Creating a 500 Error (Useful to keep around)
router.get('/500', routes.render);

// The 404 Route (ALWAYS Keep this as the last route)
router.get('/*', function(req, res){
    throw new NotFound;
});

function NotFound(msg){
    this.name = 'NotFound';
    Error.call(this, msg);
    Error.captureStackTrace(this, arguments.callee);
}

console.log('Listening on http://localhost:' + port );
<commit_msg>improve error handling code<commit_after>//setup Dependencies
var express  = require('express'),
bodyParser   = require('body-parser'),
cookieParser = require('cookie-parser'),
session      = require('express-session'),
state        = require('express-state'),
hbs          = require('./lib/exphbs'),
routes       = require('./routes'),
middleware   = require('./middleware'),
config       = require('./config'),
utils        = require('./lib/utils'),
app          = express(),
port         = (process.env.PORT || 8000),
server       = app.listen(port, function () {
    console.log("Bedrock Server listening on port " + server.address().port);
}),
router;

//Setup Express App
state.extend(app);
app.engine(hbs.extname, hbs.engine);
app.set('view engine', hbs.extname);
app.enable('view cache');

//Uncomment this if you want strict routing (ie: /foo will not resolve to /foo/)
//app.enable('strict routing');

//Change "App" to whatever your application's name is, or leave it like this.
app.set('state namespace', 'App');

//Create an empty Data object and expose it to the client. This
//will be available on the client under App.Data.
//This is just an example, so feel free to remove this.
app.expose({}, 'Data');

if (app.get('env') === 'development') {
    app.use(middleware.logger('tiny'));
}

// Set default views directory.
app.set('views', config.dirs.views);

router = express.Router({
    caseSensitive: app.get('case sensitive routing'),
    strict       : app.get('strict routing')
});

// Parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// Parse application/json
app.use(bodyParser.json())

// Parse cookies.
app.use(cookieParser());

// Session Handling
app.use(session({secret: 'keyboard cat', resave: true, saveUninitialized: true}));

// Specify the public directory.
app.use(express.static(config.dirs.pub));

// Uncomment this line if you are using Bower, and have a bower_components directory.
// Before uncommenting this line, go into config/index.js and add config.dirs.bower there.
//app.use(express.static(config.dirs.bower));

// Error handling middleware
app.use(function(err, req, res, next) {
    if(!err) return next();
    console.log(err);
    if (err.status && err.status === 404) {
        res.render('404', {error: err});
    }
    else {
        res.render('500', {error: err});
    }
});

// Use the router.
app.use(router);

///////////////////////////////////////////
//              Routes                   //
///////////////////////////////////////////

/////// ADD ALL YOUR ROUTES HERE  /////////

// The exposeTemplates() method makes the Handlebars templates that are inside /shared/templates/
// available to the client.
router.get('/', [ middleware.exposeTemplates(), routes.render('home') ]);

// A Route for Creating a 500 Error (Useful to keep around)
router.get('/500', routes.render);

//The 404 Route (ALWAYS Keep this as the last route)
router.get('/*', function(req, res, next){
    next(utils.error(404, 'Page not found'));
});<|endoftext|>


<commit_before>/**
@typedef {Object} whitelist_entry A whitelist entry
@property {string} title The title of the whitelist entry.
@property {string} url The URL for the whitelist entry.
*/

/**
@typedef {Array<whitelist_entry>} whitelist A whitelist array
*/

/**
@desc Whitelist component
*/
class Whitelist {

  /**
  @desc Initialize the instance.
  @private
  */
  constructor(email) {
    /**
    @desc Whitelist's Email
    @private
    */
    this.email = email;
  }

  /**
  @desc Add URL to whitelist.

  @param {string} title - Title for whitelist entry
  @param {string} url - URL for whitelist entry
  @return {boolean} Was successfully added to whitelist
  @throws {Error} URL is already in whitelist.
  @public
  */
  addURL(title, url) {
    // Trim whitespace from input
    title = title.trim();
    url = url.trim();
    // Validation entry input
    if (title === "") {
      throw new Error("Please enter a Title!");
    }
    if (url === "") {
      throw new Error("Please enter a URL!");
    }

    // Get whitelist
    let whitelist = this.get();

    // Check that URL is not already in whitelist
    if (_.findIndex(whitelist, (entry) => {
        return entry.url === url;
      }) !== -1) {
      // Must already be in whitelist
      // Throw an error!
      throw new Error(`URL pattern '${url}' is already in whitelist`);
    }
    // Not already in whitelist

    // Create new entry
    title = title || url;
    let entry = {
      title,
      url
    };
    // Add entry to whitelist
    whitelist.push(entry);
    // Save whitelist
    this.set(whitelist);
    // Return successful
    return true;
  }

  /**
  @desc Remove URL from whitelist
  @param {string} url - The URL to remove from the whitelist
  @return {whitelist} whitelist The updated whitelist
  @public
  */
  removeURL(url) {
    // Get whitelist
    let whitelist = this.get();
    // Find entry with matching URL in whitelist
    // Remove entry
    _.remove(whitelist, (entry) => {
      return url === entry.url
    });
    // Save new whitelist
    this.set(whitelist);
    return whitelist;
  }

  /**
  @desc Check if URL is allowed
  @param {string} url - The URL to check if whitelist allows.
  @return {boolean} Whether the URL is allowed.
  @public
  */
  isAllowed(url) {
    // Check if Chrome extension
    if (url.indexOf('chrome-extension://') !== -1) {
      return true;
    }
    // Get whitelist
    let whitelist = this.get();
    // Find entry with matching URL in whitelist
    let idx = _.findIndex(whitelist, (entry) => {
      try {
        return Whitelist.testURLs(url, entry.url);
      } catch (error) {
        console.error(error);
        return false;
      }
    });
    // Allow if not idx isnt -1
    console.log('isAllowed', url, idx !== -1);
    return idx !== -1;
  }

  /**
  @desc Get the whitelist in localStorage.

  @return {whitelist} The whitelist.
  @private
  */
  get() {
    return Whitelist.getWhitelistForEmail(this.email);
  }

  /**
  @desc Set the whitelist in localStorage.

  @param {whitelist} whitelist - The whitelist to save.
  @return {boolean} Whether successfully saved.
  @private
  */
  set(whitelist) {
    return Whitelist.setWhitelistForEmail(this.email, whitelist);
  }

  /**
  @desc Test URLs.
  @param {string} a - URL to test against. Can be a RegExp.
  @param {string} b - URL to test with.
  @return {boolean} If URL `a` matches URL `b`
  @private
  @example
  testURLs('https://google.com','*://google.com/**'); // True
  testURLs('https://google.com','*://google.ca/**'); // False
  */
  static testURLs(a, b) {
    // Ensure that a URL ends with "/" such that "/**" matches
    // Check to make sure there is a path
    if (a.split('?').length === 1 && a[a.length - 1] !== '/') {
      a += '/';
    }
    return minimatch(a, b);
  }

  /**
  @desc Get the key to lookup in localStorage for the whitelist.
  @return {string} localStorage key for the whitelist for the given email.
  @private
  */
  static getWhitelistKeyForEmail(email) {
    return 'whitelist:' + email;
  }

  /**
  @desc Get the whitelist from localStorage
  @private
  @return {whitelist} The whitelist
  @see https://developer.chrome.com/extensions/storage
  @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  */
  static getWhitelistForEmail(email) {
    let key = Whitelist.getWhitelistKeyForEmail(email);
    let whitelist = localStorage[key];
    if (typeof whitelist === 'string') {
      return JSON.parse(whitelist);
    }
    /*
      else if (typeof whitelist === 'object') {
      return whitelist;
    } */
    else {
      //console.warn('Unknown whitelist type: ', typeof whitelist, whitelist);
      return [];
    }
  }

  /**
  @desc Set the whitelist in localStorage
  @private
  @param {string} email - The admin's email address.
  @param {whitelist} whitelist - The whitelist to save.
  @return {boolean} Whether successfully saved.
  @see https://developer.chrome.com/extensions/storage
  @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  */
  static setWhitelistForEmail(email, whitelist) {
    let key = Whitelist.getWhitelistKeyForEmail(email);
    if (typeof whitelist !== 'string') {
      whitelist = JSON.stringify(whitelist);
    }
    localStorage[key] = whitelist;
    // Return successful
    return true;
  }

}

/**
@desc Moderator component
*/
class Moderator {

  /**
  @desc Initialize the instance.
  @private
  */
  constructor() {

    /**
    @desc Logged in state
    */
    this.loggedIn = false;
    /**
    @desc Moderator is in disabled state
    */
    this.isDisabled = false;
    /**
    @desc The Whitelist instance
    @private
    */
    this.whitelist = null;

    // Event listeners
    this.setupListeners();

  }

  /**
  @desc Setup all event listeners.

  @see https://developer.chrome.com/extensions/webRequest
  @listens {onBeforeRequest} Listens for before requests
  @private
  */
  setupListeners() {

    // Request listener
    chrome.webRequest.onBeforeRequest.addListener((info) => {
      var url = info.url;
      let whitelist = this.getWhitelist();
      // console.log('webRequest', this, this.isDisabled, whitelist);
      if (this.isDisabled || !whitelist) {
        return {
          cancel: false
        };
      }
      let shouldAllow = whitelist.isAllowed(url);
      // console.log('URL: ', url, shouldAllow);
      return {
        cancel: !shouldAllow
      };
    }, {
      urls: ["<all_urls>"]
    }, ["blocking"]);

    // Message Passing listener
    // chrome.runtime.onMessage.addListener(
    //   (request, sender, sendResponse) => {
    //     console.log(sender.tab ?
    //       "from a content script:" + sender.tab.url :
    //       "from the extension");
    //     if (request.type == "login") {
    //       // Login!
    //       this.session.login((error, userInfo) => {
    //         console.log('userInfo', userInfo, error);
    //         sendResponse(userInfo);
    //       });
    //     } else {
    //       console.warn('Unknown message type', request);
    //     }
    //   });

  }

  /**
  @desc Disable moderator
  */
  disable() {
    this.isDisabled = true;
  }
  /**
  @desc Enable moderator
  */
  enable() {
    this.isDisabled = false;
  }

  /**
  @desc Check if Chrome is locked.
        Locked means that an admin has signed in with their email.
  @return {boolean} Whether Chrome is locked.
  @public
  */
  isLocked() {
    return !this.isUnlocked();
  }

  /**
  @desc Check if Chrome is unlocked.
        Locked means that an admin has signed in with their email.
  @return {boolean} Whether Chrome is unlocked.
  @public
  */
  isUnlocked() {
    return !this.getEmail();
  }

  /**
  @desc Lock
  @return {boolean} Whether successfully locked
  @public
  */
  lock(email, password) {
    // Check to make sure it is not already locked
    if (this.isUnlocked()) {
      // Not already locked
      this.setEmail(email);
      this.setPassword(password);
      return this.login(email, password);
    } else {
      return this.login(email, password);
    }
  }

  /**
  @desc Unlock
  @return {boolean} Whether successfully unlocked
  @public
  */
  unlock(email, password) {
    if (this.login(email, password)) {
      // Logged in now
      this.setEmail(null);
      this.setPassword(null);
      this.whitelist = null;
      return this.logout();
    } else {
      // Could not login to unlock
      return false;
    }
  }

  /**
  @desc Login
  @return {boolean} Whether successfully logged in
  @public
  */
  login(email, password) {
    var enteredHash = CryptoJS.SHA256(password);
    var passwordHash = enteredHash.toString(CryptoJS.enc.Base64)
    if (email === this.getEmail() && passwordHash === this.getPassword()) {
      this.loggedIn = true;
      this.whitelist = new Whitelist(this.getEmail());
      return true;
    } else {
      return false;
    }
  }

  /**
  @desc logout
  @return {boolean} Whether successfully logged out
  @public
  */
  logout() {
    this.loggedIn = false;
    return true;
  }

  /**
  @desc Get administator's email.
  @private
  @return {string} Admin email.
  */
  getEmail() {
      return localStorage['admin:email'];
    }
    /**
    @desc Set administrator's email.
    @private
    @param {string} email - The new email.
    @return {void} Void.
    */
  setEmail(email) {
    if (email === null) {
      delete localStorage['admin:email'];
    } else {
      localStorage['admin:email'] = email;
    }
  }

  /**
  @desc Get administator's password.
  @private
  @return {string} Admin password.
  */
  getPassword() {
      return localStorage['admin:password'];
    }
    /**
    @desc Set administrator's password.
    @private
    @param {string} password - The new password.
    @return {void} Void.
    */
  setPassword(password) {
    if (password === null) {
      delete localStorage['admin:password'];
    } else {
      var hash = CryptoJS.SHA256(password);
      localStorage['admin:password'] = hash.toString(CryptoJS.enc.Base64);
    }
  }

  /**
  @desc Get the current Whitelist instance.
  @return {Object} The whitelist instance.
  @private
  */
  getWhitelist() {
    return this.whitelist;
  }

  /**
  @desc Get the serialized JSON form of the Whitelist.
  @return {whitelist} The whitelist JSON.
  @public
  */
  getWhitelistJSON() {
    let whitelist = this.getWhitelist();
    if (whitelist) {
      return whitelist.get();
    } else {
      return [];
    }
  }

  /**
  @desc Add to Whitelist
  @return {boolean} Whether successfully added to whitelist.
  @public
  */
  addToWhitelist(title, url) {
    if (this.loggedIn && this.whitelist) {
      this.whitelist.addURL(title, url);
      return true;
    } else {
      return false;
    }
  }

  /**
  @desc Remove from Whitelist
  @return {boolean} Whether successfully removed from whitelist.
  @public
  */
  removeFromWhitelist(url) {
    if (this.loggedIn && this.whitelist) {
      this.whitelist.removeURL(url);
      return true;
    } else {
      return false;
    }
  }

}

/**
===== Main =====
Start the background script

@ignore
*/
let moderator = window.moderator = new Moderator();<commit_msg>Improve matching for URL patterns ending with /**<commit_after>/**
@typedef {Object} whitelist_entry A whitelist entry
@property {string} title The title of the whitelist entry.
@property {string} url The URL for the whitelist entry.
*/

/**
@typedef {Array<whitelist_entry>} whitelist A whitelist array
*/

/**
@desc Whitelist component
*/
class Whitelist {

  /**
  @desc Initialize the instance.
  @private
  */
  constructor(email) {
    /**
    @desc Whitelist's Email
    @private
    */
    this.email = email;
  }

  /**
  @desc Add URL to whitelist.

  @param {string} title - Title for whitelist entry
  @param {string} url - URL for whitelist entry
  @return {boolean} Was successfully added to whitelist
  @throws {Error} URL is already in whitelist.
  @public
  */
  addURL(title, url) {
    // Trim whitespace from input
    title = title.trim();
    url = url.trim();
    // Validation entry input
    if (title === "") {
      throw new Error("Please enter a Title!");
    }
    if (url === "") {
      throw new Error("Please enter a URL!");
    }

    // Get whitelist
    let whitelist = this.get();

    // Check that URL is not already in whitelist
    if (_.findIndex(whitelist, (entry) => {
        return entry.url === url;
      }) !== -1) {
      // Must already be in whitelist
      // Throw an error!
      throw new Error(`URL pattern '${url}' is already in whitelist`);
    }
    // Not already in whitelist

    // Create new entry
    title = title || url;
    let entry = {
      title,
      url
    };
    // Add entry to whitelist
    whitelist.push(entry);
    // Save whitelist
    this.set(whitelist);
    // Return successful
    return true;
  }

  /**
  @desc Remove URL from whitelist
  @param {string} url - The URL to remove from the whitelist
  @return {whitelist} whitelist The updated whitelist
  @public
  */
  removeURL(url) {
    // Get whitelist
    let whitelist = this.get();
    // Find entry with matching URL in whitelist
    // Remove entry
    _.remove(whitelist, (entry) => {
      return url === entry.url
    });
    // Save new whitelist
    this.set(whitelist);
    return whitelist;
  }

  /**
  @desc Check if URL is allowed
  @param {string} url - The URL to check if whitelist allows.
  @return {boolean} Whether the URL is allowed.
  @public
  */
  isAllowed(url) {
    // Check if Chrome extension
    if (url.indexOf('chrome-extension://') !== -1) {
      return true;
    }
    // Get whitelist
    let whitelist = this.get();
    // Find entry with matching URL in whitelist
    let idx = _.findIndex(whitelist, (entry) => {
      try {
        return Whitelist.testURLs(url, entry.url);
      } catch (error) {
        console.error(error);
        return false;
      }
    });
    // Allow if not idx isnt -1
    console.log('isAllowed', url, idx !== -1);
    return idx !== -1;
  }

  /**
  @desc Get the whitelist in localStorage.

  @return {whitelist} The whitelist.
  @private
  */
  get() {
    return Whitelist.getWhitelistForEmail(this.email);
  }

  /**
  @desc Set the whitelist in localStorage.

  @param {whitelist} whitelist - The whitelist to save.
  @return {boolean} Whether successfully saved.
  @private
  */
  set(whitelist) {
    return Whitelist.setWhitelistForEmail(this.email, whitelist);
  }

  /**
  @desc Test URLs.
  @param {string} a - URL to test against. Can be a RegExp.
  @param {string} b - URL to test with.
  @return {boolean} If URL `a` matches URL `b`
  @private
  @example
  testURLs('https://google.com','*://google.com/**'); // True
  testURLs('https://google.com','*://google.ca/**'); // False
  */
  static testURLs(a, b) {
    // Ensure that a URL ends with "/" such that "/**" matches
    // Check to make sure there is a path
    if (_.endsWith(b, '/**') && a.split('?').length === 1 && a[a.length - 1] !== '/') {
      a += '/';
    }
    return minimatch(a, b);
  }

  /**
  @desc Get the key to lookup in localStorage for the whitelist.
  @return {string} localStorage key for the whitelist for the given email.
  @private
  */
  static getWhitelistKeyForEmail(email) {
    return 'whitelist:' + email;
  }

  /**
  @desc Get the whitelist from localStorage
  @private
  @return {whitelist} The whitelist
  @see https://developer.chrome.com/extensions/storage
  @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  */
  static getWhitelistForEmail(email) {
    let key = Whitelist.getWhitelistKeyForEmail(email);
    let whitelist = localStorage[key];
    if (typeof whitelist === 'string') {
      return JSON.parse(whitelist);
    }
    /*
      else if (typeof whitelist === 'object') {
      return whitelist;
    } */
    else {
      //console.warn('Unknown whitelist type: ', typeof whitelist, whitelist);
      return [];
    }
  }

  /**
  @desc Set the whitelist in localStorage
  @private
  @param {string} email - The admin's email address.
  @param {whitelist} whitelist - The whitelist to save.
  @return {boolean} Whether successfully saved.
  @see https://developer.chrome.com/extensions/storage
  @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  */
  static setWhitelistForEmail(email, whitelist) {
    let key = Whitelist.getWhitelistKeyForEmail(email);
    if (typeof whitelist !== 'string') {
      whitelist = JSON.stringify(whitelist);
    }
    localStorage[key] = whitelist;
    // Return successful
    return true;
  }

}

/**
@desc Moderator component
*/
class Moderator {

  /**
  @desc Initialize the instance.
  @private
  */
  constructor() {

    /**
    @desc Logged in state
    */
    this.loggedIn = false;
    /**
    @desc Moderator is in disabled state
    */
    this.isDisabled = false;
    /**
    @desc The Whitelist instance
    @private
    */
    this.whitelist = null;

    // Event listeners
    this.setupListeners();

  }

  /**
  @desc Setup all event listeners.

  @see https://developer.chrome.com/extensions/webRequest
  @listens {onBeforeRequest} Listens for before requests
  @private
  */
  setupListeners() {

    // Request listener
    chrome.webRequest.onBeforeRequest.addListener((info) => {
      var url = info.url;
      let whitelist = this.getWhitelist();
      // console.log('webRequest', this, this.isDisabled, whitelist);
      if (this.isDisabled || !whitelist) {
        return {
          cancel: false
        };
      }
      let shouldAllow = whitelist.isAllowed(url);
      // console.log('URL: ', url, shouldAllow);
      return {
        cancel: !shouldAllow
      };
    }, {
      urls: ["<all_urls>"]
    }, ["blocking"]);

    // Message Passing listener
    // chrome.runtime.onMessage.addListener(
    //   (request, sender, sendResponse) => {
    //     console.log(sender.tab ?
    //       "from a content script:" + sender.tab.url :
    //       "from the extension");
    //     if (request.type == "login") {
    //       // Login!
    //       this.session.login((error, userInfo) => {
    //         console.log('userInfo', userInfo, error);
    //         sendResponse(userInfo);
    //       });
    //     } else {
    //       console.warn('Unknown message type', request);
    //     }
    //   });

  }

  /**
  @desc Disable moderator
  */
  disable() {
    this.isDisabled = true;
  }
  /**
  @desc Enable moderator
  */
  enable() {
    this.isDisabled = false;
  }

  /**
  @desc Check if Chrome is locked.
        Locked means that an admin has signed in with their email.
  @return {boolean} Whether Chrome is locked.
  @public
  */
  isLocked() {
    return !this.isUnlocked();
  }

  /**
  @desc Check if Chrome is unlocked.
        Locked means that an admin has signed in with their email.
  @return {boolean} Whether Chrome is unlocked.
  @public
  */
  isUnlocked() {
    return !this.getEmail();
  }

  /**
  @desc Lock
  @return {boolean} Whether successfully locked
  @public
  */
  lock(email, password) {
    // Check to make sure it is not already locked
    if (this.isUnlocked()) {
      // Not already locked
      this.setEmail(email);
      this.setPassword(password);
      return this.login(email, password);
    } else {
      return this.login(email, password);
    }
  }

  /**
  @desc Unlock
  @return {boolean} Whether successfully unlocked
  @public
  */
  unlock(email, password) {
    if (this.login(email, password)) {
      // Logged in now
      this.setEmail(null);
      this.setPassword(null);
      this.whitelist = null;
      return this.logout();
    } else {
      // Could not login to unlock
      return false;
    }
  }

  /**
  @desc Login
  @return {boolean} Whether successfully logged in
  @public
  */
  login(email, password) {
    var enteredHash = CryptoJS.SHA256(password);
    var passwordHash = enteredHash.toString(CryptoJS.enc.Base64)
    if (email === this.getEmail() && passwordHash === this.getPassword()) {
      this.loggedIn = true;
      this.whitelist = new Whitelist(this.getEmail());
      return true;
    } else {
      return false;
    }
  }

  /**
  @desc logout
  @return {boolean} Whether successfully logged out
  @public
  */
  logout() {
    this.loggedIn = false;
    return true;
  }

  /**
  @desc Get administator's email.
  @private
  @return {string} Admin email.
  */
  getEmail() {
      return localStorage['admin:email'];
    }
    /**
    @desc Set administrator's email.
    @private
    @param {string} email - The new email.
    @return {void} Void.
    */
  setEmail(email) {
    if (email === null) {
      delete localStorage['admin:email'];
    } else {
      localStorage['admin:email'] = email;
    }
  }

  /**
  @desc Get administator's password.
  @private
  @return {string} Admin password.
  */
  getPassword() {
      return localStorage['admin:password'];
    }
    /**
    @desc Set administrator's password.
    @private
    @param {string} password - The new password.
    @return {void} Void.
    */
  setPassword(password) {
    if (password === null) {
      delete localStorage['admin:password'];
    } else {
      var hash = CryptoJS.SHA256(password);
      localStorage['admin:password'] = hash.toString(CryptoJS.enc.Base64);
    }
  }

  /**
  @desc Get the current Whitelist instance.
  @return {Object} The whitelist instance.
  @private
  */
  getWhitelist() {
    return this.whitelist;
  }

  /**
  @desc Get the serialized JSON form of the Whitelist.
  @return {whitelist} The whitelist JSON.
  @public
  */
  getWhitelistJSON() {
    let whitelist = this.getWhitelist();
    if (whitelist) {
      return whitelist.get();
    } else {
      return [];
    }
  }

  /**
  @desc Add to Whitelist
  @return {boolean} Whether successfully added to whitelist.
  @public
  */
  addToWhitelist(title, url) {
    if (this.loggedIn && this.whitelist) {
      this.whitelist.addURL(title, url);
      return true;
    } else {
      return false;
    }
  }

  /**
  @desc Remove from Whitelist
  @return {boolean} Whether successfully removed from whitelist.
  @public
  */
  removeFromWhitelist(url) {
    if (this.loggedIn && this.whitelist) {
      this.whitelist.removeURL(url);
      return true;
    } else {
      return false;
    }
  }

}

/**
===== Main =====
Start the background script

@ignore
*/
let moderator = window.moderator = new Moderator();<|endoftext|>


<commit_before>/* jshint node: true */

var pkg = require('../package.json');
var resources = require('ember-eureka/config/structure').resources;

module.exports = {
    name: pkg.name,
    version: 1,
    port: 4000,
    enableCORS: true,
    schemas: resources,
    database: {
        adapter: 'rdf',
        config: {
            store: 'virtuoso',
            host: process.env.DB_PORT_8890_TCP_ADDR,
            port: process.env.DB_PORT_8890_TCP_PORT,
            graphURI: 'http://'+pkg.name+'.com'
        }
    }
};<commit_msg>add publicDirectory in server's config<commit_after>/* jshint node: true */

var pkg = require('../package.json');
var resources = require('ember-eureka/config/structure').resources;

module.exports = {
    name: pkg.name,
    version: 1,
    port: 4000,
    enableCORS: true,
    schemas: resources,
    publicDirectory: '/dist',
    database: {
        adapter: 'rdf',
        config: {
            store: 'virtuoso',
            host: process.env.DB_PORT_8890_TCP_ADDR,
            port: process.env.DB_PORT_8890_TCP_PORT,
            graphURI: 'http://<%= dasherizedPackageName %>.com'
        }
    }
};<|endoftext|>


<commit_before>//case for UnaryExpression
;"undefined" == typeof window.test && undefined === null && function (e) {
    window.test = +e;
    window.test = -e;
    window.test = !e;
}(window);<commit_msg>update check<commit_after>//case for UnaryExpression
;
"undefined" == typeof window.test && undefined === null && function (e) {
    window.test = +e;
    window.test = -e;
    window.test = !e;
}(window);<|endoftext|>


<commit_before>export default function createEagerSchema({embedCode, properties}) {
  embedCode = JSON.stringify(embedCode)

  const initializeApp = function initializeApp(embedCodeInjection) {
    if (!window.addEventListener) return // Check for IE9+

    const TRACKED_ENTITY_PATTERN = /TRACKED_ENTITY\[(\S+)\]/g
    const options = INSTALL_OPTIONS

    const insertOption = (match, key) => options[key]

    function insertEmbedCode() {
      document.head.innerHTML += embedCodeInjection.replace(TRACKED_ENTITY_PATTERN, insertOption)

      eval(document.head.lastChild.textContent) // eslint-disable-line no-eval
    }

    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", insertEmbedCode)
    }
    else {
      insertEmbedCode()
    }
  }.toString()

  const installJSON = {
    resources: {
      body: [
        {
          type: "script",
          contents: `(${initializeApp}(${embedCode}))`
        }
      ]
    },

    options: {properties}
  }

  return installJSON
}
<commit_msg>Support multiple tags in embed code.<commit_after>export default function createEagerSchema({embedCode, properties}) {
  embedCode = JSON.stringify(embedCode)

  const initializeApp = function initializeApp(embedCodeInjection) {
    if (!window.addEventListener) return // Check for IE9+

    const TRACKED_ENTITY_PATTERN = /TRACKED_ENTITY\[(\S+)\]/g
    const options = INSTALL_OPTIONS

    const insertOption = (match, key) => options[key]

    function insertEmbedCode() {
      const serializer = document.createElement("div")

      serializer.innerHTML = embedCodeInjection.replace(TRACKED_ENTITY_PATTERN, insertOption)

      Array.prototype.forEach.call(serializer.children, element => {
        document.body.appendChild(element)

        if (element.nodeName === "SCRIPT") {
          eval(element.textContent) // eslint-disable-line no-eval
        }
      })
    }

    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", insertEmbedCode)
    }
    else {
      insertEmbedCode()
    }
  }.toString()

  const installJSON = {
    resources: {
      body: [
        {
          type: "script",
          contents: `(${initializeApp}(${embedCode}))`
        }
      ]
    },

    options: {properties}
  }

  return installJSON
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'

import ExpandableList from './ExpandableList'
import List from './List'
import Close, { CloseIcon } from './Close'

import { focus } from './utility/focus'

// `PureComponent` is only available in React >= 15.3.0.
const PureComponent = React.PureComponent || React.Component

export default class ExpandableMenu extends PureComponent
{
	static propTypes =
	{
		// Component CSS class
		className  : PropTypes.string,

		// CSS style object
		style      : PropTypes.object,

		// `aria-label` for the "Close" button
		// (which is an "x" visible in fullscreen mode).
		closeLabel : PropTypes.string,

		// The "x" button icon that closes the `<Select/>`
		// in fullscreen mode on mobile devices.
		closeButtonIcon : PropTypes.oneOfType([PropTypes.func, PropTypes.oneOf([false])]).isRequired,

		toggler : PropTypes.func,
		togglerAriaLabel : PropTypes.string,
		togglerAriaHasPopup : PropTypes.string,
		togglerClassName : PropTypes.string
	}

	static defaultProps =
	{
		// The "x" button icon that closes the `<Select/>`
		// in fullscreen mode on mobile devices.
		closeButtonIcon : CloseIcon
	}

	state = {}

	onExpand = () => this.setState({ isExpanded: true })

	onCollapse = ({ focusOut }) =>
	{
		if (!focusOut) {
			this.focus()
		}
		this.setState({ isExpanded: false })
	}

	// `this.toggler` is deprecated.
	focus = () => focus(this.toggler || this.togglerNode)

	expand   = () => this.list.expand()
	collapse = () => this.list.collapse()
	toggle   = () => this.list.toggle()

	onFocusOut = () => {
		// `window.rruiCollapseOnFocusOut` can be used
		// for debugging expandable contents.
		if (window.rruiCollapseOnFocusOut !== false) {
			this.collapse()
		}
	}

	storeListRef = (ref) => this.list = ref

	// (legacy) (deprecated)
	// Is used to focus legacy togglers.
	storeTogglerRef = (ref) => this.toggler = ref

	// `this.togglerNode` is only used to determine
	// whether the focus is "inside" the component or "outside" of it.
	storeTogglerNode = (node) => this.togglerNode = node
	getTogglerNode = () => this.togglerNode

	render()
	{
		const
		{
			upward,
			alignment,
			scrollIntoView,
			closeButtonIcon,
			closeLabel,
			style,
			className,
			toggler,
			togglerAriaLabel,
			togglerAriaHasPopup,
			togglerClassName,
			children
		}
		= this.props

		const { isExpanded } = this.state

		let menuToggler
		let menuItems

		if (toggler) {
			menuItems = children
			const togglerElement = React.createElement(toggler)
			menuToggler = (
				<button
					ref={ this.storeTogglerNode }
					onClick={ this.onClick }
					onKeyDown={ this.onKeyDown }
					onBlur={ this.onBlur }
					aria-haspopup={ togglerAriaHasPopup }
					aria-label={ togglerAriaLabel }
					aria-expanded={ togglerAriaHasPopup ? (isExpanded ? true : false) : undefined }
					className={ togglerClassName }>
					{ togglerElement }
				</button>
			)
		} else {
			menuItems = React.Children.toArray(children)
			menuToggler = menuItems.shift()
			menuToggler = (
				<div
					ref={ this.storeTogglerNode }
					onClick={ this.onClick }
					onKeyDown={ this.onKeyDown }
					onBlur={ this.onBlur }>
					{ React.cloneElement(menuToggler, { ref : this.storeTogglerRef }) }
				</div>
			)
		}

		return (
			<div
				style={ style }
				className={ classNames('rrui__menu', className) }>

				{menuToggler}

				<ExpandableList
					ref={this.storeListRef}
					upward={upward}
					alignment={alignment}
					scrollIntoView={scrollIntoView}
					scrollMaxItems={0}
					onCollapse={this.onCollapse}
					onExpand={this.onExpand}
					onTapOutside={this.onFocusOut}
					onFocusOut={this.onFocusOut}
					getTogglerNode={this.getTogglerNode}
					closeButtonIcon={closeButtonIcon}
					closeLabel={closeLabel}
					focusSelectedItem={false}
					className="rrui__shadow">
					{menuItems}
				</ExpandableList>
			</div>
		)
	}

	onBlur = (event) => this.list && this.list.onBlur(event)

	onClick = (event) =>
	{
		const { disabled } = this.props

		if (!disabled) {
			this.toggle()
		}
	}

	onKeyDown = (event) =>
	{
		const { disabled } = this.props

		if (disabled) {
			return
		}

		if (event.defaultPrevented) {
			return
		}

		if (event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) {
			return
		}

		switch (event.keyCode)
		{
			// "Up" arrow.
			// Select the previous item (if present).
			case 38:
			// "Down" arrow.
			// Select the next item (if present).
			case 40:
				return this.list.onKeyDown(event)

			// "Enter".
			case 13:
				// Submit containing `<form/>`.
				// Expand otherwise.
				this.expand()
				return event.preventDefault()
		}
	}
}<commit_msg>ExpandableMenu `aria-expanded`<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'

import ExpandableList from './ExpandableList'
import List from './List'
import Close, { CloseIcon } from './Close'

import { focus } from './utility/focus'

// `PureComponent` is only available in React >= 15.3.0.
const PureComponent = React.PureComponent || React.Component

export default class ExpandableMenu extends PureComponent
{
	static propTypes =
	{
		// Component CSS class
		className  : PropTypes.string,

		// CSS style object
		style      : PropTypes.object,

		// `aria-label` for the "Close" button
		// (which is an "x" visible in fullscreen mode).
		closeLabel : PropTypes.string,

		// The "x" button icon that closes the `<Select/>`
		// in fullscreen mode on mobile devices.
		closeButtonIcon : PropTypes.oneOfType([PropTypes.func, PropTypes.oneOf([false])]).isRequired,

		toggler : PropTypes.func,
		togglerAriaLabel : PropTypes.string,
		togglerAriaHasPopup : PropTypes.string,
		togglerClassName : PropTypes.string
	}

	static defaultProps =
	{
		// The "x" button icon that closes the `<Select/>`
		// in fullscreen mode on mobile devices.
		closeButtonIcon : CloseIcon
	}

	state = {}

	onExpand = () => this.setState({ isExpanded: true })

	onCollapse = ({ focusOut }) =>
	{
		if (!focusOut) {
			this.focus()
		}
		this.setState({ isExpanded: false })
	}

	// `this.toggler` is deprecated.
	focus = () => focus(this.toggler || this.togglerNode)

	expand   = () => this.list.expand()
	collapse = () => this.list.collapse()
	toggle   = () => this.list.toggle()

	onFocusOut = () => {
		// `window.rruiCollapseOnFocusOut` can be used
		// for debugging expandable contents.
		if (window.rruiCollapseOnFocusOut !== false) {
			this.collapse()
		}
	}

	storeListRef = (ref) => this.list = ref

	// (legacy) (deprecated)
	// Is used to focus legacy togglers.
	storeTogglerRef = (ref) => this.toggler = ref

	// `this.togglerNode` is only used to determine
	// whether the focus is "inside" the component or "outside" of it.
	storeTogglerNode = (node) => this.togglerNode = node
	getTogglerNode = () => this.togglerNode

	render()
	{
		const
		{
			upward,
			alignment,
			scrollIntoView,
			closeButtonIcon,
			closeLabel,
			style,
			className,
			toggler,
			togglerAriaLabel,
			togglerAriaHasPopup,
			togglerClassName,
			children
		}
		= this.props

		const { isExpanded } = this.state

		let menuToggler
		let menuItems

		if (toggler) {
			menuItems = children
			const togglerElement = React.createElement(toggler)
			menuToggler = (
				<button
					ref={ this.storeTogglerNode }
					onClick={ this.onClick }
					onKeyDown={ this.onKeyDown }
					onBlur={ this.onBlur }
					aria-haspopup={ togglerAriaHasPopup }
					aria-label={ togglerAriaLabel }
					aria-expanded={ isExpanded ? true : false }
					className={ togglerClassName }>
					{ togglerElement }
				</button>
			)
		} else {
			menuItems = React.Children.toArray(children)
			menuToggler = menuItems.shift()
			menuToggler = (
				<div
					ref={ this.storeTogglerNode }
					onClick={ this.onClick }
					onKeyDown={ this.onKeyDown }
					onBlur={ this.onBlur }>
					{ React.cloneElement(menuToggler, { ref : this.storeTogglerRef }) }
				</div>
			)
		}

		return (
			<div
				style={ style }
				className={ classNames('rrui__menu', className) }>

				{menuToggler}

				<ExpandableList
					ref={this.storeListRef}
					upward={upward}
					alignment={alignment}
					scrollIntoView={scrollIntoView}
					scrollMaxItems={0}
					onCollapse={this.onCollapse}
					onExpand={this.onExpand}
					onTapOutside={this.onFocusOut}
					onFocusOut={this.onFocusOut}
					getTogglerNode={this.getTogglerNode}
					closeButtonIcon={closeButtonIcon}
					closeLabel={closeLabel}
					focusSelectedItem={false}
					className="rrui__shadow">
					{menuItems}
				</ExpandableList>
			</div>
		)
	}

	onBlur = (event) => this.list && this.list.onBlur(event)

	onClick = (event) =>
	{
		const { disabled } = this.props

		if (!disabled) {
			this.toggle()
		}
	}

	onKeyDown = (event) =>
	{
		const { disabled } = this.props

		if (disabled) {
			return
		}

		if (event.defaultPrevented) {
			return
		}

		if (event.ctrlKey || event.altKey || event.shiftKey || event.metaKey) {
			return
		}

		switch (event.keyCode)
		{
			// "Up" arrow.
			// Select the previous item (if present).
			case 38:
			// "Down" arrow.
			// Select the next item (if present).
			case 40:
				return this.list.onKeyDown(event)

			// "Enter".
			case 13:
				// Submit containing `<form/>`.
				// Expand otherwise.
				this.expand()
				return event.preventDefault()
		}
	}
}<|endoftext|>


<commit_before>(function(cloudStack, testData) {
  cloudStack.sections.domains = {
    title: 'Domains',
    id: 'domains',

    // Domain tree
    treeView: {
      // Details
      detailView: {
        name: 'Domain details',
        viewAll: {
          label: 'Accounts',
          path: 'accounts'
        },

        // Detail actions
        actions: {
          'delete': {
            label: 'Delete domain',
            messages: {
              confirm: function(args) {
                return 'Are you sure you want to delete this domain?'
              },
              notification: function(args) {
                return 'Domain is deleted';
              }
            },

            preFilter: function(args) {
              if(isAdmin()) {
                args.$form.find('.form-item[rel=isForced]').css('display', 'inline-block');
              }
            },

            createForm: {
              title: 'Delete domain',
              fields: {
                isForced: {
                  label: 'Force delete',
                  isBoolean: true,
                  isHidden: true
                }
              }
            },

            action: function(args) {
              var array1 = [];
              debugger;
              if(args.$form.find('.form-item[rel=isForced]').css("display") != "none") //uncomment after Brian fix it to include $form in args
                array1.push("&cleanup=" + (args.data.isForced == "on"));

              $.ajax({
                url: createURL("deleteDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var jid = json.deletedomainresponse.jobid;
                  args.response.success(
                    {_custom:
                     {jobId: jid}
                    }
                  );
                }
              });
            },
            notification: {
              poll: pollAsyncJobResult
            }
          },

          // Edit domain
          edit: {
            label: 'Edit domain details',
            messages: {
              notification: function(args) {
                return 'Edited domain: ' + args.name;
              }
            },
            action: function(args) {
              var array1 = [];
              array1.push("&name=" + todb(args.data.name));
              $.ajax({
                url: createURL("updateDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                success: function(json) {
                  debugger;
                  args.response.success({data: json.updatedomainresponse.domain});
                }
              });
            }
          },

          // Add domain
          create: {
            label: 'Add domain',

            action: function(args) {
              var array1 = [];
              array1.push("&name=" + todb(args.data.name));
              array1.push("&parentdomainid=" + args.context.domains[0].id);
              $.ajax({
                url: createURL("createDomain" + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var item = json.createdomainresponse.domain;
                  args.response.success({data: item});
                }
              });
            },

            messages: {
              notification: function(args) {
                return 'Created domain'
              }
            },

            createForm: {
              title: 'Add subdomain',
              desc: 'Please specify the subdomain you want to create under this domain',
              fields: {
                name: {
                  label: 'Name',
                  validation: { required: true }
                }
              }
            },

            notification: {
              poll: testData.notifications.testPoll
            }
          }
        },
        tabs: {
          details: {
            title: 'Details',
            fields: [
              {
                name: { label: 'Name', isEditable: true }
              },
              {
                id: { label: 'ID' },
                accountTotal: { label: 'Accounts' },
                vmTotal: { label: 'Instances' },
                volumeTotal: { label: 'Volumes' }
              }
            ],
            dataProvider: function(args) {
              var domainObj = args.context.domains[0];
              $.ajax({
                url: createURL("listAccounts&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listaccountsresponse.account;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["accountTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVirtualMachines&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvirtualmachinesresponse.virtualmachine;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["vmTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVolumes&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvolumesresponse.volume;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["volumeTotal"] = total;
                }
              });

              args.response.success({
                data: domainObj
              });
            }
          },
          adminAccounts: {
            title: 'Admin Accounts',
            multiple: true,
            fields: [
              {
                name: { label: 'Name' },
                vmtotal: { label: 'VMs' },
                iptotal: { label: 'IPs' },
                receivedbytes: { label: 'Bytes received' },
                sentbytes: { label: 'Bytes sent' },
                state: { label: 'State' }
              }
            ],
            dataProvider: function(args) {
              args.response.success({
                data: $.grep(testData.data.accounts, function(item, index) {
                  return item.domain === 'ROOT' && index <= 5;
                })
              });
            }
          },
          resourceLimits: {
            title: 'Resource Limits',
            fields: {
              vmlimit: { label: 'Instance Limit' },
              iplimit: { label: 'Public IP Limit' },
              volumelimit: { label: 'Volume Limit' },
              snapshotlimit: { label: 'Snapshot Limit' },
              templatelimit: { label: 'Template Limit' }
            },
            dataProvider: function(args) {
              args.response.success({
                data: testData.data.accounts[4]
              });
            }
          }
        }
      },
      labelField: 'name',
      dataProvider: function(args) {
        var parentDomain = args.context.parentDomain;
        if(parentDomain == null) { //draw root node
          $.ajax({
            url: createURL("listDomains&id=" + g_domainid),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainsresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
        else {
          $.ajax({
            url: createURL("listDomainChildren&id=" + parentDomain.id),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainchildrenresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
      }
    }
  };

  var domainActionfilter = function(args) {
    var jsonObj = args.context.item;
    var allowedActions = [];
    if(isAdmin()) {
      allowedActions.push("add");
    	if(jsonObj.id != 1) { //"ROOT" domain is not allowed to edit or delete
        allowedActions.push("edit"); //merge updateResourceCount into edit
	      allowedActions.push("delete");
    	}
    }
	  //allowedActions.push("updateResourceCount");
    return allowedActions;
  }

})(cloudStack, testData);
<commit_msg>cloudStack 3.0 new UI - domain page - add VM limits, IP limits, Volume limits, Snapshot limits, Template limits field.<commit_after>(function(cloudStack, testData) {
  cloudStack.sections.domains = {
    title: 'Domains',
    id: 'domains',

    // Domain tree
    treeView: {
      // Details
      detailView: {
        name: 'Domain details',
        viewAll: {
          label: 'Accounts',
          path: 'accounts'
        },

        // Detail actions
        actions: {
          'delete': {
            label: 'Delete domain',
            messages: {
              confirm: function(args) {
                return 'Are you sure you want to delete this domain?'
              },
              notification: function(args) {
                return 'Domain is deleted';
              }
            },

            preFilter: function(args) {
              if(isAdmin()) {
                args.$form.find('.form-item[rel=isForced]').css('display', 'inline-block');
              }
            },

            createForm: {
              title: 'Delete domain',
              fields: {
                isForced: {
                  label: 'Force delete',
                  isBoolean: true,
                  isHidden: true
                }
              }
            },

            action: function(args) {
              var array1 = [];
              debugger;
              if(args.$form.find('.form-item[rel=isForced]').css("display") != "none") //uncomment after Brian fix it to include $form in args
                array1.push("&cleanup=" + (args.data.isForced == "on"));

              $.ajax({
                url: createURL("deleteDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var jid = json.deletedomainresponse.jobid;
                  args.response.success(
                    {_custom:
                     {jobId: jid}
                    }
                  );
                }
              });
            },
            notification: {
              poll: pollAsyncJobResult
            }
          },

          // Edit domain
          edit: {
            label: 'Edit domain details',
            messages: {
              notification: function(args) {
                return 'Edited domain: ' + args.name;
              }
            },
            action: function(args) {
              var array1 = [];
              array1.push("&name=" + todb(args.data.name));
              $.ajax({
                url: createURL("updateDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                success: function(json) {
                  debugger;
                  args.response.success({data: json.updatedomainresponse.domain});
                }
              });
            }
          },

          // Add domain
          create: {
            label: 'Add domain',

            action: function(args) {
              var array1 = [];
              array1.push("&name=" + todb(args.data.name));
              array1.push("&parentdomainid=" + args.context.domains[0].id);
              $.ajax({
                url: createURL("createDomain" + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var item = json.createdomainresponse.domain;
                  args.response.success({data: item});
                }
              });
            },

            messages: {
              notification: function(args) {
                return 'Created domain'
              }
            },

            createForm: {
              title: 'Add subdomain',
              desc: 'Please specify the subdomain you want to create under this domain',
              fields: {
                name: {
                  label: 'Name',
                  validation: { required: true }
                }
              }
            },

            notification: {
              poll: testData.notifications.testPoll
            }
          }
        },
        tabs: {
          details: {
            title: 'Details',
            fields: [
              {
                name: { label: 'Name', isEditable: true }
              },
              {
                id: { label: 'ID' },
                vmLimit: {
                  label: 'Instance limits',
                  isEditable: true
                },
                ipLimit: {
                  label: 'Public IP limits',
                  isEditable: true
                },
                volumeLimit: {
                  label: 'Volume limits',
                  isEditable: true
                },
                snapshotLimit: {
                  label: 'Snapshot limits',
                  isEditable: true
                },
                templateLimit: {
                  label: 'Template limits',
                  isEditable: true
                },
                accountTotal: { label: 'Accounts' },
                vmTotal: { label: 'Instances' },
                volumeTotal: { label: 'Volumes' }
              }
            ],
            dataProvider: function(args) {
              var domainObj = args.context.domains[0];
              $.ajax({
                url: createURL("listAccounts&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listaccountsresponse.account;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["accountTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVirtualMachines&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvirtualmachinesresponse.virtualmachine;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["vmTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVolumes&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvolumesresponse.volume;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["volumeTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listResourceLimits&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var limits = json.listresourcelimitsresponse.resourcelimit;
                  if (limits != null) {
                    for (var i = 0; i < limits.length; i++) {
                      var limit = limits[i];
                      switch (limit.resourcetype) {
                        case "0":
                          domainObj["vmLimit"] = limit.max;
                          break;
                        case "1":
                          domainObj["ipLimit"] = limit.max;
                          break;
                        case "2":
                          domainObj["volumeLimit"] = limit.max;
                          break;
                        case "3":
                          domainObj["snapshotLimit"] = limit.max;
                          break;
                        case "4":
                          domainObj["templateLimit"] = limit.max;
                          break;
                      }
                    }
                  }
                }
              });

              args.response.success({
                data: domainObj
              });
            }
          },
          adminAccounts: {
            title: 'Admin Accounts',
            multiple: true,
            fields: [
              {
                name: { label: 'Name' },
                vmtotal: { label: 'VMs' },
                iptotal: { label: 'IPs' },
                receivedbytes: { label: 'Bytes received' },
                sentbytes: { label: 'Bytes sent' },
                state: { label: 'State' }
              }
            ],
            dataProvider: function(args) {
              args.response.success({
                data: $.grep(testData.data.accounts, function(item, index) {
                  return item.domain === 'ROOT' && index <= 5;
                })
              });
            }
          },
          resourceLimits: {
            title: 'Resource Limits',
            fields: {
              vmlimit: { label: 'Instance Limit' },
              iplimit: { label: 'Public IP Limit' },
              volumelimit: { label: 'Volume Limit' },
              snapshotlimit: { label: 'Snapshot Limit' },
              templatelimit: { label: 'Template Limit' }
            },
            dataProvider: function(args) {
              args.response.success({
                data: testData.data.accounts[4]
              });
            }
          }
        }
      },
      labelField: 'name',
      dataProvider: function(args) {
        var parentDomain = args.context.parentDomain;
        if(parentDomain == null) { //draw root node
          $.ajax({
            url: createURL("listDomains&id=" + g_domainid),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainsresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
        else {
          $.ajax({
            url: createURL("listDomainChildren&id=" + parentDomain.id),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainchildrenresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
      }
    }
  };

  var domainActionfilter = function(args) {
    var jsonObj = args.context.item;
    var allowedActions = [];
    if(isAdmin()) {
      allowedActions.push("add");
    	if(jsonObj.id != 1) { //"ROOT" domain is not allowed to edit or delete
        allowedActions.push("edit"); //merge updateResourceCount into edit
	      allowedActions.push("delete");
    	}
    }
	  //allowedActions.push("updateResourceCount");
    return allowedActions;
  }

})(cloudStack, testData);
<|endoftext|>


<commit_before>$(function () {
    $('#notifications').popover({html: true, content: 'Loading...', trigger: 'manual'});

    $("#notifications").click(function () {
        if ($(".popover").is(":visible")) {
            $("#notifications").popover('hide');
        }
        else {
            $("#notifications").popover('show');
            $.ajax({
                url: '/notifications/last/',
                beforeSend: function () {
                    $(".popover-content").html("

");
                    $("#notifications").removeClass("new-notifications");
                },
                success: function (data) {
                    $(".popover-content").html(data);
                }
            });
        }
        return false;
    });

    function check_notifications() {
        var socket = new WebSocket('ws://' + window.location.host + '/notifications/');
        socket.onopen = function open() {
            console.log('WebSockets connection created to notifications channel.');
        };

        socket.onmessage = function message(event) {
            var data = JSON.parse(event.data);
            // NOTE: We escape JavaScript to prevent XSS attacks.
            var username = encodeURI(data['username']);

            if (data['is_logged_in']) {
                $("#notifications").addClass("new-notifications");
            }
            else {
                $("#notifications").removeClass("new-notifications");
            }
        };

        if (socket.readyState == WebSocket.OPEN) {
            socket.onopen();
        };
    };
    /* function check_notifications() {
        $.ajax({
            url: '/notifications/check/',
            cache: false,
            success: function (data) {
                if (data != "0") {
                    $("#notifications").addClass("new-notifications");
                }
                else {
                    $("#notifications").removeClass("new-notifications");
                }
            },
            complete: function () {
                window.setTimeout(check_notifications, 30000);
            }
        });
    }; */
    check_notifications();
});<commit_msg>Adding the necessary frontend functionality.<commit_after>$(function () {
    $('#notifications').popover({html: true, content: 'Loading...', trigger: 'manual'});

    $("#notifications").click(function () {
        if ($(".popover").is(":visible")) {
            $("#notifications").popover('hide');
        }
        else {
            $("#notifications").popover('show');
            $.ajax({
                url: '/notifications/last/',
                beforeSend: function () {
                    $(".popover-content").html("

");
                    $("#notifications").removeClass("new-notifications");
                },
                success: function (data) {
                    $(".popover-content").html(data);
                }
            });
        }
        return false;
    });

    // Correctly decide between ws:// and wss://
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var ws_path = ws_scheme + '://' + window.location.host + "/notifications/";
    var webSocket = new channels.WebSocketBridge();
    webSocket.connect(ws_path);

    // Helpful debugging
    webSocket.socket.onopen = function () {
        console.log("Connected to notifications stream at: " + ws_path);
    };

    webSocket.socket.onclose = function () {
        console.log("Disconnected from notifications stream at: " + ws_path);
    };

    webSocket.listen(function(event) {
        // NOTE: We escape JavaScript to prevent XSS attacks.
        // var data = JSON.parse(event);
        // var username = encodeURI(data['username']);
        if (event.activity_type === "notification") {
            $("#notifications").addClass("new-notifications");
            console.log("User " + event.username + " just " + event.activity)
        }
        else {
            $("#notifications").removeClass("new-notifications");
        }
    });
});
<|endoftext|>


<commit_before>/**!
 *
 * Copyright (c) 2015-2016 Cisco Systems, Inc. See LICENSE file.
 * @private
 */

import {patterns} from '@ciscospark/common';
import {SparkPlugin} from '@ciscospark/spark-core';
import {isArray, isFunction, isString} from 'lodash';
import S from 'string';

const Normalizer = SparkPlugin.extend({
  namespace: `Conversation`,

  /**
   * Adjust properties on object received from the api to address
   * inconsistencies. in particular, ensures that all Person objects are
   * identified by UUIDs rather than email addresses.
   * @param {Object} object
   * @returns {Promise}
   */
  normalize(object) {
    if (isArray(object)) {
      return Promise.all(object.map((o) => this.normalize(o)))
        .then(() => object);
    }

    if (!object.objectType) {
      return Promise.reject(new Error(`Cannot normalize \`object\` without \objectType\``));
    }

    const methodName = `normalize${S(object.objectType).capitalize().s}`;
    const promises = [];
    if (this[methodName]) {
      promises.push(this[methodName](object));
    }

    [
      `content`,
      `displayName`
    ].forEach((property) => {
      if (typeof object[property] === `string`) {
        if (object[property].length === 0) {
          Reflect.deleteProperty(object, property);
        }
        else {
          promises.push(this.normalizeProperty(object, property));
        }
      }
    });

    return Promise.all(promises)
      .then(() => object);
  },

  normalizeProperty(object, property) {
    if (!isString(property)) {
      throw new Error(`property is required`);
    }

    const normalizer = S(`normalize_prop_${property}`)
      .camelize()
      .s;

    if (isFunction(this[normalizer])) {
      return this[normalizer](object[property])
        .then((value) => {
          object[property] = value;
          return object;
        });
    }

    return Promise.resolve();
  },

  /**
   * @param {Object} conversation
   * @private
   * @returns {Promise}
   */
  normalizeConversation(conversation) {
    conversation.activities = conversation.activities || {};
    conversation.activities.items = conversation.activities.items || [];
    conversation.participants = conversation.participants || {};
    conversation.participants.items = conversation.participants.items || [];

    return Promise.all([
      Promise.all(conversation.activities.items.map((item) => this.normalize(item))),
      Promise.all(conversation.participants.items.map((item) => this.normalize(item)))
    ])
      .then(() => conversation);
  },

  /**
   * @param {Object} activity
   * @private
   * @returns {Promise}
   */
  normalizeActivity(activity) {
    return Promise.all([`actor`, `object`, `target`].map((key) => {
      if (activity[key]) {
        return this.normalize(activity[key]);
      }
      return Promise.resolve();
    }))
      .then(() => activity);
  },

  /**
   * @param {Object} person
   * @private
   * @returns {Promise}
   */
  normalizePerson(person) {
    const email = person.entryEmail || person.emailAddress || person.id;
    const id = person.entryUUID || person.id;

    if (patterns.email.test(email)) {
      person.entryEmail = person.emailAddress = email.toLowerCase();
    }
    else {
      Reflect.deleteProperty(person, `entryEmail`);
      Reflect.deleteProperty(person, `emailAddress`);
    }

    if (patterns.uuid.test(id)) {
      person.entryUUID = person.id = id.toLowerCase();
      return Promise.resolve(person);
    }

    if (!email) {
      return Promise.reject(new Error(`cannot determine id without an \`emailAddress\` or \`entryUUID\` property`));
    }

    return this.spark.user.asUUID(email)
      .then((uuid) => {
        person.entryUUID = person.id = uuid;
        return person;
      });
  },

  normalizePropContent(content) {
    return this.filter(content);
  }
});

export default Normalizer;
<commit_msg>refactor(plugin-conversation): verify Normalizer#filter is implemented<commit_after>/**!
 *
 * Copyright (c) 2015-2016 Cisco Systems, Inc. See LICENSE file.
 * @private
 */

import {patterns} from '@ciscospark/common';
import {SparkPlugin} from '@ciscospark/spark-core';
import {isArray, isFunction, isString} from 'lodash';
import S from 'string';

const Normalizer = SparkPlugin.extend({
  namespace: `Conversation`,

  initialize(...args) {
    Reflect.apply(SparkPlugin.prototype.initialize, this, args);
    if (!this.filter) {
      throw new Error(`Normalizer#filter() must be implemented`);
    }
  },

  /**
   * Adjust properties on object received from the api to address
   * inconsistencies. in particular, ensures that all Person objects are
   * identified by UUIDs rather than email addresses.
   * @param {Object} object
   * @returns {Promise}
   */
  normalize(object) {
    if (isArray(object)) {
      return Promise.all(object.map((o) => this.normalize(o)))
        .then(() => object);
    }

    if (!object.objectType) {
      return Promise.reject(new Error(`Cannot normalize \`object\` without \objectType\``));
    }

    const methodName = `normalize${S(object.objectType).capitalize().s}`;
    const promises = [];
    if (this[methodName]) {
      promises.push(this[methodName](object));
    }

    [
      `content`,
      `displayName`
    ].forEach((property) => {
      if (typeof object[property] === `string`) {
        if (object[property].length === 0) {
          Reflect.deleteProperty(object, property);
        }
        else {
          promises.push(this.normalizeProperty(object, property));
        }
      }
    });

    return Promise.all(promises)
      .then(() => object);
  },

  normalizeProperty(object, property) {
    if (!isString(property)) {
      throw new Error(`property is required`);
    }

    const normalizer = S(`normalize_prop_${property}`)
      .camelize()
      .s;

    if (isFunction(this[normalizer])) {
      return this[normalizer](object[property])
        .then((value) => {
          object[property] = value;
          return object;
        });
    }

    return Promise.resolve();
  },

  /**
   * @param {Object} conversation
   * @private
   * @returns {Promise}
   */
  normalizeConversation(conversation) {
    conversation.activities = conversation.activities || {};
    conversation.activities.items = conversation.activities.items || [];
    conversation.participants = conversation.participants || {};
    conversation.participants.items = conversation.participants.items || [];

    return Promise.all([
      Promise.all(conversation.activities.items.map((item) => this.normalize(item))),
      Promise.all(conversation.participants.items.map((item) => this.normalize(item)))
    ])
      .then(() => conversation);
  },

  /**
   * @param {Object} activity
   * @private
   * @returns {Promise}
   */
  normalizeActivity(activity) {
    return Promise.all([`actor`, `object`, `target`].map((key) => {
      if (activity[key]) {
        return this.normalize(activity[key]);
      }
      return Promise.resolve();
    }))
      .then(() => activity);
  },

  /**
   * @param {Object} person
   * @private
   * @returns {Promise}
   */
  normalizePerson(person) {
    const email = person.entryEmail || person.emailAddress || person.id;
    const id = person.entryUUID || person.id;

    if (patterns.email.test(email)) {
      person.entryEmail = person.emailAddress = email.toLowerCase();
    }
    else {
      Reflect.deleteProperty(person, `entryEmail`);
      Reflect.deleteProperty(person, `emailAddress`);
    }

    if (patterns.uuid.test(id)) {
      person.entryUUID = person.id = id.toLowerCase();
      return Promise.resolve(person);
    }

    if (!email) {
      return Promise.reject(new Error(`cannot determine id without an \`emailAddress\` or \`entryUUID\` property`));
    }

    return this.spark.user.asUUID(email)
      .then((uuid) => {
        person.entryUUID = person.id = uuid;
        return person;
      });
  },

  normalizePropContent(content) {
    return this.filter(content);
  }
});

export default Normalizer;
<|endoftext|>


<commit_before>var async = require('async');

var panel = module.exports;

/**
 * The permission() hook.
 */
panel.permission = function(permissions, callback) {
  var newPermissions = {};

  newPermissions['manage-panels'] = {
    title: 'Manage panels',
    description: 'List, create and edit panels.'
  };

  callback(null, newPermissions);
};

/**
 * The type() hook.
 */
panel.type = function(types, callback) {
  var newTypes = {};

  newTypes['panel'] = {
    title: 'Panel',
    description: 'A piece of content to be displayed on a layout region.',
    polymorphic: true,
    fields: {
      name: {
        title: 'Name',
        type: 'text',
        required: 'true',
        weight: -15
      },
      title: {
        title: 'Title',
        type: 'text',
        required: 'true',
        weight: -5
      }
    },
    access: {
      'list': 'manage-panels',
      'load': 'manage-panels',
      'add': 'manage-panels',
      'edit': 'manage-panels',
      'delete': 'manage-panels'
    }
  };

  callback(null, newTypes);
};

/**
 * The panelType() hook.
 */
panel.panelType = function(panelTypes, callback) {
  var newTypes = {};

  newTypes['list'] = {
    title: 'List panel',
    description: 'A item list panel.',
    fields: {
      itemType: {
        title: 'Item type',
        type:  'text',
        required: true
      }
    }
  };

  newTypes['item'] = {
    title: 'Item panel',
    description: 'A single item panel.',
    fields: {
      itemType: {
        title: 'Item type',
        type:  'text',
        required: true
      },
      itemKey: {
        title: 'Item key',
        type:  'text',
        required: true
      }
    }
  };

  newTypes['form'] = {
    title: 'Form panel',
    description: 'A form panel.',
    fields: {
      formName: {
        title: 'Form',
        type:  'reference',
        reference: {
          type: 'form'
        },
        required: true
      },
      redirect: {
        title: 'Redirect',
        type: 'text',
        description: 'Enter a path to redirect user upon successful form submission.'
      }
    }
  };

  callback(null, newTypes);
}

/**
 * The panel() hook.
 */
panel.panel = function(panels, callback) {
  var newPanels = {}

  newPanels['brand'] = {
    title: 'Brand',
    description: 'Application name or logo.',
    bare: true,
    content: this.application.settings.application.name
  }

  callback(null, newPanels);
};

/**
 * The contextReactionType() hook.
 */
panel.contextReactionType = function(reactionTypes, callback) {
  var self = this;
  var newReactionTypes = {};

  newReactionTypes['panel'] = {
    title: 'Show panels',
    description: 'Show panels on one or more layout regions.',
    standalone: false,
    fields: {
      panels: {
        title: 'Panels',
        description: 'Panels to show.',
        type: 'reference',
        reference: {
          type: 'panelReaction',
          multiple: true,
          inline: true,
          index: 'region'
        }
      }
    },
    react: function(request, response, regionPanels, callback) {
      // Initialize panels container if not initialized yet.
      response.payload.panels = response.payload.panels || {};

      // Add all panels to response payload.
      async.each(Object.keys(regionPanels), function(regionName, next) {
        // Initialize panels container if not initialized yet.
        response.payload.panels[regionName] = response.payload.panels[regionName] || [];
        var panels = regionPanels[regionName];
        // A context can set several panels for a region.
        async.each(panels, function(regionPanel, next) {
          // Load the panel.
          var Panel = self.application.type('panel');

          Panel.load(regionPanel.name, function(err, panel) {
            if (err) {
              return callback(err);
            }

            if (panel) {
              // Set panel weight and add it to the region.
              panel.weight = regionPanel.weight;
              response.payload.panels[regionName].push(panel);
            }
            next();
          });

        }, function() {
          next();
        });
      }, function(err) {
        if (err) {
          return callback(err);
        }
        callback();
      });
    }
  };

  callback(null, newReactionTypes);
};
<commit_msg>Adding missing types referenced by the panel context reaction type.<commit_after>var async = require('async');

var panel = module.exports;

/**
 * The permission() hook.
 */
panel.permission = function(permissions, callback) {
  var newPermissions = {};

  newPermissions['manage-panels'] = {
    title: 'Manage panels',
    description: 'List, create and edit panels.'
  };

  callback(null, newPermissions);
};

/**
 * The type() hook.
 */
panel.type = function(types, callback) {
  var newTypes = {};

  newTypes['panel'] = {
    title: 'Panel',
    description: 'A piece of content to be displayed on a layout region.',
    polymorphic: true,
    fields: {
      name: {
        title: 'Name',
        type: 'text',
        required: 'true',
        weight: -15
      },
      title: {
        title: 'Title',
        type: 'text',
        required: 'true',
        weight: -5
      }
    },
    access: {
      'list': 'manage-panels',
      'load': 'manage-panels',
      'add': 'manage-panels',
      'edit': 'manage-panels',
      'delete': 'manage-panels'
    }
  };

  newTypes['panelReaction'] = {
    title: 'Panel reaction',
    formTitle: 'Region',
    description: 'Panel reaction item used on panel context reaction.',
    standalone: false,
    fields: {
      region: {
        title: 'Region',
        description: 'Region to add the panel.',
        type: 'text'
      },
      panels: {
        title: 'Panels',
        description: 'Panels to show.',
        type: 'reference',
        reference: {
          type: 'panelReactionPanel',
          multiple: true,
          inline: true
        }
      }
    }
  };

  newTypes['panelReactionPanel'] = {
    title: 'Panel reaction panel',
    formTitle: 'Panel',
    description: 'Panel reaction item panel used on panel context reaction.',
    standalone: false,
    fields: {
      panel: {
        title: 'Panel',
        type: 'reference',
        reference: {
          type: 'panel'
        }
      },
      weight: {
        title: 'Weight',
        type: 'text'
      }
    }
  };

  callback(null, newTypes);
};

/**
 * The panelType() hook.
 */
panel.panelType = function(panelTypes, callback) {
  var newTypes = {};

  newTypes['list'] = {
    title: 'List panel',
    description: 'A item list panel.',
    fields: {
      itemType: {
        title: 'Item type',
        type:  'text',
        required: true
      }
    }
  };

  newTypes['item'] = {
    title: 'Item panel',
    description: 'A single item panel.',
    fields: {
      itemType: {
        title: 'Item type',
        type:  'text',
        required: true
      },
      itemKey: {
        title: 'Item key',
        type:  'text',
        required: true
      }
    }
  };

  newTypes['form'] = {
    title: 'Form panel',
    description: 'A form panel.',
    fields: {
      formName: {
        title: 'Form',
        type:  'reference',
        reference: {
          type: 'form'
        },
        required: true
      },
      redirect: {
        title: 'Redirect',
        type: 'text',
        description: 'Enter a path to redirect user upon successful form submission.'
      }
    }
  };

  callback(null, newTypes);
}

/**
 * The panel() hook.
 */
panel.panel = function(panels, callback) {
  var newPanels = {}

  newPanels['brand'] = {
    title: 'Brand',
    description: 'Application name or logo.',
    bare: true,
    content: this.application.settings.application.name
  }

  callback(null, newPanels);
};

/**
 * The contextReactionType() hook.
 */
panel.contextReactionType = function(reactionTypes, callback) {
  var self = this;
  var newReactionTypes = {};

  newReactionTypes['panel'] = {
    title: 'Show panels',
    description: 'Show panels on one or more layout regions.',
    standalone: false,
    fields: {
      panels: {
        title: 'Panels',
        description: 'Panels to show.',
        type: 'reference',
        reference: {
          type: 'panelReaction',
          multiple: true,
          inline: true,
          index: 'region'
        }
      }
    },
    react: function(request, response, regionPanels, callback) {
      // Initialize panels container if not initialized yet.
      response.payload.panels = response.payload.panels || {};

      // Add all panels to response payload.
      async.each(Object.keys(regionPanels), function(regionName, next) {
        // Initialize panels container if not initialized yet.
        response.payload.panels[regionName] = response.payload.panels[regionName] || [];
        var panels = regionPanels[regionName];
        // A context can set several panels for a region.
        async.each(panels, function(regionPanel, next) {
          // Load the panel.
          var Panel = self.application.type('panel');

          Panel.load(regionPanel.name, function(err, panel) {
            if (err) {
              return callback(err);
            }

            if (panel) {
              // Set panel weight and add it to the region.
              panel.weight = regionPanel.weight;
              response.payload.panels[regionName].push(panel);
            }
            next();
          });

        }, function() {
          next();
        });
      }, function(err) {
        if (err) {
          return callback(err);
        }
        callback();
      });
    }
  };

  callback(null, newReactionTypes);
};
<|endoftext|>