<commit_before>(function () {
  'use strict';

  angular
      .module('material.components.tabs')
      .controller('MdTabsController', MdTabsController);

  function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $mdInkRipple, $mdUtil) {
    var ctrl = this,
        elements = getElements();

    ctrl.scope = $scope;
    ctrl.parent = $scope.$parent;
    ctrl.tabs = [];
    ctrl.lastSelectedIndex = null;
    ctrl.focusIndex = 0;
    ctrl.offsetLeft = 0;
    ctrl.hasContent = true;
    ctrl.hasFocus = false;
    ctrl.lastClick = false;

    ctrl.redirectFocus = redirectFocus;
    ctrl.attachRipple = attachRipple;
    ctrl.shouldStretchTabs = shouldStretchTabs;
    ctrl.shouldPaginate = shouldPaginate;
    ctrl.insertTab = insertTab;
    ctrl.removeTab = removeTab;
    ctrl.select = select;
    ctrl.scroll = scroll;
    ctrl.nextPage = nextPage;
    ctrl.previousPage = previousPage;
    ctrl.keydown = keydown;
    ctrl.canPageForward = canPageForward;
    ctrl.canPageBack = canPageBack;
    ctrl.refreshIndex = refreshIndex;
    ctrl.incrementSelectedIndex = incrementSelectedIndex;
    ctrl.updateInkBarStyles = updateInkBarStyles;

    init();

    function init () {
      $scope.$watch('selectedIndex', handleSelectedIndexChange);
      $scope.$watch('$mdTabsCtrl.focusIndex', handleFocusIndexChange);
      $scope.$watch('$mdTabsCtrl.offsetLeft', handleOffsetChange);
      angular.element($window).on('resize', function () { $scope.$apply(handleWindowResize); });
      $timeout(updateInkBarStyles, 0, false);
      $timeout(updateHeightFromContent, 0, false);
    }

    function getElements () {
      var elements      = {};

      //-- gather tab bar elements
      elements.wrapper  = $element[0].getElementsByTagName('md-tabs-wrapper')[0];
      elements.canvas   = elements.wrapper.getElementsByTagName('md-tabs-canvas')[0];
      elements.paging   = elements.canvas.getElementsByTagName('md-pagination-wrapper')[0];
      elements.tabs     = elements.paging.getElementsByTagName('md-tab-item');
      elements.dummies  = elements.canvas.getElementsByTagName('md-dummy-tab');
      elements.inkBar   = elements.paging.getElementsByTagName('md-ink-bar')[0];

      //-- gather tab content elements
      elements.contentsWrapper = $element[0].getElementsByTagName('md-tabs-content-wrapper')[0];
      elements.contents = elements.contentsWrapper.getElementsByTagName('md-tab-content');

      return elements;
    }

    function keydown (event) {
      switch (event.keyCode) {
        case $mdConstant.KEY_CODE.LEFT_ARROW:
          event.preventDefault();
          incrementSelectedIndex(-1, true);
          break;
        case $mdConstant.KEY_CODE.RIGHT_ARROW:
          event.preventDefault();
          incrementSelectedIndex(1, true);
          break;
        case $mdConstant.KEY_CODE.SPACE:
        case $mdConstant.KEY_CODE.ENTER:
          event.preventDefault();
          $scope.selectedIndex = ctrl.focusIndex;
          break;
      }
      ctrl.lastClick = false;
    }

    function incrementSelectedIndex (inc, focus) {
      var newIndex,
          index = focus ? ctrl.focusIndex : $scope.selectedIndex;
      for (newIndex = index + inc;
           ctrl.tabs[newIndex] && ctrl.tabs[newIndex].scope.disabled;
           newIndex += inc) {}
      if (ctrl.tabs[newIndex]) {
        if (focus) ctrl.focusIndex = newIndex;
        else $scope.selectedIndex = newIndex;
      }
    }

    function handleOffsetChange (left) {
      angular.element(elements.paging).css('left', '-' + left + 'px');
      $scope.$broadcast('$mdTabsPaginationChanged');
    }

    function handleFocusIndexChange (newIndex, oldIndex) {
      if (newIndex === oldIndex) return;
      if (!elements.tabs[newIndex]) return;
      adjustOffset();
      redirectFocus();
    }

    function redirectFocus () {
      elements.dummies[ctrl.focusIndex].focus();
    }

    function adjustOffset () {
      var tab = elements.tabs[ctrl.focusIndex],
          left = tab.offsetLeft,
          right = tab.offsetWidth + left;
      ctrl.offsetLeft = Math.max(ctrl.offsetLeft, fixOffset(right - elements.canvas.clientWidth));
      ctrl.offsetLeft = Math.min(ctrl.offsetLeft, fixOffset(left));
    }

    function handleWindowResize () {
      ctrl.lastSelectedIndex = $scope.selectedIndex;
      updateInkBarStyles();
      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);
    }

    function insertTab (tabData, index) {
      var proto = {
            getIndex: function () { return ctrl.tabs.indexOf(tab); },
            isActive: function () { return this.getIndex() === $scope.selectedIndex; },
            isLeft:   function () { return this.getIndex() < $scope.selectedIndex; },
            isRight:  function () { return this.getIndex() > $scope.selectedIndex; },
            hasFocus: function () { return !ctrl.lastClick && ctrl.hasFocus && this.getIndex() === ctrl.focusIndex; },
            id:       $mdUtil.nextUid()
          },
          tab = angular.extend(proto, tabData);
      if (!angular.isString(tabData.template)) {
        ctrl.hasContent = false;
        $element.addClass('md-no-tab-content');
      }
      if (angular.isDefined(index)) {
        ctrl.tabs.splice(index, 0, tab);
      } else {
        ctrl.tabs.push(tab);
      }
      return tab;
    }

    function removeTab (tabData) {
      ctrl.tabs.splice(tabData.getIndex(), 1);
      refreshIndex();
      $timeout(function () {
        updateInkBarStyles();
        ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);
      });
    }

    function refreshIndex () {
      $scope.selectedIndex = getNearestSafeIndex($scope.selectedIndex);
      ctrl.focusIndex = getNearestSafeIndex(ctrl.focusIndex);
    }

    function handleSelectedIndexChange (newValue, oldValue) {
      if (newValue === oldValue) return;
      $scope.selectedIndex = getNearestSafeIndex(newValue);
      ctrl.lastSelectedIndex = oldValue;
      updateInkBarStyles();
      updateHeightFromContent();
      $scope.$broadcast('$mdTabsChanged');
    }

    function handleResizeWhenVisible () {
      //-- if there is already a watcher waiting for resize, do nothing
      if (handleResizeWhenVisible.watcher) return;
      //-- otherwise, we will abuse the $watch function to check for visible
      handleResizeWhenVisible.watcher = $scope.$watch(function () {
        //-- since we are checking for DOM size, we use $timeout to wait for after the DOM updates
        $timeout(function () {
          //-- if the watcher has already run (ie. multiple digests in one cycle), do nothing
          if (!handleResizeWhenVisible.watcher) return;

          if ($element.prop('offsetParent')) {
            handleResizeWhenVisible.watcher();
            handleResizeWhenVisible.watcher = null;

            //-- we have to trigger our own $apply so that the DOM bindings will update
            $scope.$apply(handleWindowResize);
          }
        }, 0, false);
      });
    }

    function updateHeightFromContent () {
      if (!$scope.dynamicHeight) return $element.css('height', '');
      var tabContent = elements.contents[$scope.selectedIndex],
          contentHeight = tabContent.offsetHeight,
          tabsHeight    = elements.wrapper.offsetHeight,
          newHeight     = contentHeight + tabsHeight;
      $element.css('height', newHeight + 'px');
    }

    function updateInkBarStyles () {
      if (!ctrl.tabs.length) return;
      //-- if the element is not visible, we will not be able to calculate sizes until it is
      //-- we should treat that as a resize event rather than just updating the ink bar
      if (!$element.prop('offsetParent')) return handleResizeWhenVisible();
      var index = $scope.selectedIndex,
          totalWidth = elements.paging.offsetWidth,
          tab = elements.tabs[index],
          left = tab.offsetLeft,
          right = totalWidth - left - tab.offsetWidth;
      updateInkBarClassName();
      angular.element(elements.inkBar).css({ left: left + 'px', right: right + 'px' });
    }

    function updateInkBarClassName () {
      var newIndex = $scope.selectedIndex,
          oldIndex = ctrl.lastSelectedIndex,
          ink = angular.element(elements.inkBar);
      ink.removeClass('md-left md-right');
      if (!angular.isNumber(oldIndex)) return;
      if (newIndex < oldIndex) {
        ink.addClass('md-left');
      } else if (newIndex > oldIndex) {
        ink.addClass('md-right');
      }
    }

    function getNearestSafeIndex(newIndex) {
      var maxOffset = Math.max(ctrl.tabs.length - newIndex, newIndex),
          i, tab;
      for (i = 0; i <= maxOffset; i++) {
        tab = ctrl.tabs[newIndex + i];
        if (tab && (tab.scope.disabled !== true)) return tab.getIndex();
        tab = ctrl.tabs[newIndex - i];
        if (tab && (tab.scope.disabled !== true)) return tab.getIndex();
      }
      return newIndex;
    }

    function shouldStretchTabs () {
      switch ($scope.stretchTabs) {
        case 'always': return true;
        case 'never':  return false;
        default:       return !shouldPaginate() && $window.matchMedia('(max-width: 600px)').matches;
      }
    }

    function shouldPaginate () {
      var canvasWidth = $element.prop('clientWidth');
      angular.forEach(elements.tabs, function (tab) { canvasWidth -= tab.offsetWidth; });
      return canvasWidth < 0;
    }

    function select (index) {
      ctrl.focusIndex = $scope.selectedIndex = index;
      ctrl.lastClick = true;
    }

    function scroll (event) {
      if (!shouldPaginate()) return;
      event.preventDefault();
      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft - event.wheelDelta);
    }

    function fixOffset (value) {
      var lastTab = elements.tabs[elements.tabs.length - 1],
          totalWidth = lastTab.offsetLeft + lastTab.offsetWidth;
      value = Math.max(0, value);
      value = Math.min(totalWidth - elements.canvas.clientWidth, value);
      return value;
    }

    function nextPage () {
      var viewportWidth = elements.canvas.clientWidth,
          totalWidth = viewportWidth + ctrl.offsetLeft,
          i, tab;
      for (i = 0; i < elements.tabs.length; i++) {
        tab = elements.tabs[i];
        if (tab.offsetLeft + tab.offsetWidth > totalWidth) break;
      }
      ctrl.offsetLeft = fixOffset(tab.offsetLeft);
    }

    function previousPage () {
      var i, tab;
      for (i = 0; i < elements.tabs.length; i++) {
        tab = elements.tabs[i];
        if (tab.offsetLeft + tab.offsetWidth >= ctrl.offsetLeft) break;
      }
      ctrl.offsetLeft = fixOffset(tab.offsetLeft + tab.offsetWidth - elements.canvas.clientWidth);
    }

    function canPageBack () {
      return ctrl.offsetLeft > 0;
    }

    function canPageForward () {
      var lastTab = elements.tabs[elements.tabs.length - 1];
      return lastTab && lastTab.offsetLeft + lastTab.offsetWidth > elements.canvas.clientWidth + ctrl.offsetLeft;
    }

    function attachRipple (scope, element) {
      var options = { colorElement: angular.element(elements.inkBar) };
      $mdInkRipple.attachTabBehavior(scope, element, options);
    }
  }
})();<commit_msg>feat(tabs): adds support for `label` attribute without tab content<commit_after>(function () {
  'use strict';

  angular
      .module('material.components.tabs')
      .controller('MdTabsController', MdTabsController);

  function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $mdInkRipple, $mdUtil) {
    var ctrl = this,
        elements = getElements();

    ctrl.scope = $scope;
    ctrl.parent = $scope.$parent;
    ctrl.tabs = [];
    ctrl.lastSelectedIndex = null;
    ctrl.focusIndex = 0;
    ctrl.offsetLeft = 0;
    ctrl.hasContent = true;
    ctrl.hasFocus = false;
    ctrl.lastClick = false;

    ctrl.redirectFocus = redirectFocus;
    ctrl.attachRipple = attachRipple;
    ctrl.shouldStretchTabs = shouldStretchTabs;
    ctrl.shouldPaginate = shouldPaginate;
    ctrl.insertTab = insertTab;
    ctrl.removeTab = removeTab;
    ctrl.select = select;
    ctrl.scroll = scroll;
    ctrl.nextPage = nextPage;
    ctrl.previousPage = previousPage;
    ctrl.keydown = keydown;
    ctrl.canPageForward = canPageForward;
    ctrl.canPageBack = canPageBack;
    ctrl.refreshIndex = refreshIndex;
    ctrl.incrementSelectedIndex = incrementSelectedIndex;
    ctrl.updateInkBarStyles = updateInkBarStyles;

    init();

    function init () {
      $scope.$watch('selectedIndex', handleSelectedIndexChange);
      $scope.$watch('$mdTabsCtrl.focusIndex', handleFocusIndexChange);
      $scope.$watch('$mdTabsCtrl.offsetLeft', handleOffsetChange);
      angular.element($window).on('resize', function () { $scope.$apply(handleWindowResize); });
      $timeout(updateInkBarStyles, 0, false);
      $timeout(updateHeightFromContent, 0, false);
    }

    function getElements () {
      var elements      = {};

      //-- gather tab bar elements
      elements.wrapper  = $element[0].getElementsByTagName('md-tabs-wrapper')[0];
      elements.canvas   = elements.wrapper.getElementsByTagName('md-tabs-canvas')[0];
      elements.paging   = elements.canvas.getElementsByTagName('md-pagination-wrapper')[0];
      elements.tabs     = elements.paging.getElementsByTagName('md-tab-item');
      elements.dummies  = elements.canvas.getElementsByTagName('md-dummy-tab');
      elements.inkBar   = elements.paging.getElementsByTagName('md-ink-bar')[0];

      //-- gather tab content elements
      elements.contentsWrapper = $element[0].getElementsByTagName('md-tabs-content-wrapper')[0];
      elements.contents = elements.contentsWrapper.getElementsByTagName('md-tab-content');

      return elements;
    }

    function keydown (event) {
      switch (event.keyCode) {
        case $mdConstant.KEY_CODE.LEFT_ARROW:
          event.preventDefault();
          incrementSelectedIndex(-1, true);
          break;
        case $mdConstant.KEY_CODE.RIGHT_ARROW:
          event.preventDefault();
          incrementSelectedIndex(1, true);
          break;
        case $mdConstant.KEY_CODE.SPACE:
        case $mdConstant.KEY_CODE.ENTER:
          event.preventDefault();
          $scope.selectedIndex = ctrl.focusIndex;
          break;
      }
      ctrl.lastClick = false;
    }

    function incrementSelectedIndex (inc, focus) {
      var newIndex,
          index = focus ? ctrl.focusIndex : $scope.selectedIndex;
      for (newIndex = index + inc;
           ctrl.tabs[newIndex] && ctrl.tabs[newIndex].scope.disabled;
           newIndex += inc) {}
      if (ctrl.tabs[newIndex]) {
        if (focus) ctrl.focusIndex = newIndex;
        else $scope.selectedIndex = newIndex;
      }
    }

    function handleOffsetChange (left) {
      angular.element(elements.paging).css('left', '-' + left + 'px');
      $scope.$broadcast('$mdTabsPaginationChanged');
    }

    function handleFocusIndexChange (newIndex, oldIndex) {
      if (newIndex === oldIndex) return;
      if (!elements.tabs[newIndex]) return;
      adjustOffset();
      redirectFocus();
    }

    function redirectFocus () {
      elements.dummies[ctrl.focusIndex].focus();
    }

    function adjustOffset () {
      var tab = elements.tabs[ctrl.focusIndex],
          left = tab.offsetLeft,
          right = tab.offsetWidth + left;
      ctrl.offsetLeft = Math.max(ctrl.offsetLeft, fixOffset(right - elements.canvas.clientWidth));
      ctrl.offsetLeft = Math.min(ctrl.offsetLeft, fixOffset(left));
    }

    function handleWindowResize () {
      ctrl.lastSelectedIndex = $scope.selectedIndex;
      updateInkBarStyles();
      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);
    }

    function insertTab (tabData, index) {
      var proto = {
            getIndex: function () { return ctrl.tabs.indexOf(tab); },
            isActive: function () { return this.getIndex() === $scope.selectedIndex; },
            isLeft:   function () { return this.getIndex() < $scope.selectedIndex; },
            isRight:  function () { return this.getIndex() > $scope.selectedIndex; },
            hasFocus: function () { return !ctrl.lastClick && ctrl.hasFocus && this.getIndex() === ctrl.focusIndex; },
            id:       $mdUtil.nextUid()
          },
          tab = angular.extend(proto, tabData);
      if (!tabData.template) {
        ctrl.hasContent = false;
        $element.addClass('md-no-tab-content');
      }
      if (angular.isDefined(index)) {
        ctrl.tabs.splice(index, 0, tab);
      } else {
        ctrl.tabs.push(tab);
      }
      return tab;
    }

    function removeTab (tabData) {
      ctrl.tabs.splice(tabData.getIndex(), 1);
      refreshIndex();
      $timeout(function () {
        updateInkBarStyles();
        ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);
      });
    }

    function refreshIndex () {
      $scope.selectedIndex = getNearestSafeIndex($scope.selectedIndex);
      ctrl.focusIndex = getNearestSafeIndex(ctrl.focusIndex);
    }

    function handleSelectedIndexChange (newValue, oldValue) {
      if (newValue === oldValue) return;
      $scope.selectedIndex = getNearestSafeIndex(newValue);
      ctrl.lastSelectedIndex = oldValue;
      updateInkBarStyles();
      updateHeightFromContent();
      $scope.$broadcast('$mdTabsChanged');
    }

    function handleResizeWhenVisible () {
      //-- if there is already a watcher waiting for resize, do nothing
      if (handleResizeWhenVisible.watcher) return;
      //-- otherwise, we will abuse the $watch function to check for visible
      handleResizeWhenVisible.watcher = $scope.$watch(function () {
        //-- since we are checking for DOM size, we use $timeout to wait for after the DOM updates
        $timeout(function () {
          //-- if the watcher has already run (ie. multiple digests in one cycle), do nothing
          if (!handleResizeWhenVisible.watcher) return;

          if ($element.prop('offsetParent')) {
            handleResizeWhenVisible.watcher();
            handleResizeWhenVisible.watcher = null;

            //-- we have to trigger our own $apply so that the DOM bindings will update
            $scope.$apply(handleWindowResize);
          }
        }, 0, false);
      });
    }

    function updateHeightFromContent () {
      if (!$scope.dynamicHeight) return $element.css('height', '');
      var tabContent = elements.contents[$scope.selectedIndex],
          contentHeight = tabContent.offsetHeight,
          tabsHeight    = elements.wrapper.offsetHeight,
          newHeight     = contentHeight + tabsHeight;
      $element.css('height', newHeight + 'px');
    }

    function updateInkBarStyles () {
      if (!ctrl.tabs.length) return;
      //-- if the element is not visible, we will not be able to calculate sizes until it is
      //-- we should treat that as a resize event rather than just updating the ink bar
      if (!$element.prop('offsetParent')) return handleResizeWhenVisible();
      var index = $scope.selectedIndex,
          totalWidth = elements.paging.offsetWidth,
          tab = elements.tabs[index],
          left = tab.offsetLeft,
          right = totalWidth - left - tab.offsetWidth;
      updateInkBarClassName();
      angular.element(elements.inkBar).css({ left: left + 'px', right: right + 'px' });
    }

    function updateInkBarClassName () {
      var newIndex = $scope.selectedIndex,
          oldIndex = ctrl.lastSelectedIndex,
          ink = angular.element(elements.inkBar);
      ink.removeClass('md-left md-right');
      if (!angular.isNumber(oldIndex)) return;
      if (newIndex < oldIndex) {
        ink.addClass('md-left');
      } else if (newIndex > oldIndex) {
        ink.addClass('md-right');
      }
    }

    function getNearestSafeIndex(newIndex) {
      var maxOffset = Math.max(ctrl.tabs.length - newIndex, newIndex),
          i, tab;
      for (i = 0; i <= maxOffset; i++) {
        tab = ctrl.tabs[newIndex + i];
        if (tab && (tab.scope.disabled !== true)) return tab.getIndex();
        tab = ctrl.tabs[newIndex - i];
        if (tab && (tab.scope.disabled !== true)) return tab.getIndex();
      }
      return newIndex;
    }

    function shouldStretchTabs () {
      switch ($scope.stretchTabs) {
        case 'always': return true;
        case 'never':  return false;
        default:       return !shouldPaginate() && $window.matchMedia('(max-width: 600px)').matches;
      }
    }

    function shouldPaginate () {
      var canvasWidth = $element.prop('clientWidth');
      angular.forEach(elements.tabs, function (tab) { canvasWidth -= tab.offsetWidth; });
      return canvasWidth < 0;
    }

    function select (index) {
      ctrl.focusIndex = $scope.selectedIndex = index;
      ctrl.lastClick = true;
    }

    function scroll (event) {
      if (!shouldPaginate()) return;
      event.preventDefault();
      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft - event.wheelDelta);
    }

    function fixOffset (value) {
      var lastTab = elements.tabs[elements.tabs.length - 1],
          totalWidth = lastTab.offsetLeft + lastTab.offsetWidth;
      value = Math.max(0, value);
      value = Math.min(totalWidth - elements.canvas.clientWidth, value);
      return value;
    }

    function nextPage () {
      var viewportWidth = elements.canvas.clientWidth,
          totalWidth = viewportWidth + ctrl.offsetLeft,
          i, tab;
      for (i = 0; i < elements.tabs.length; i++) {
        tab = elements.tabs[i];
        if (tab.offsetLeft + tab.offsetWidth > totalWidth) break;
      }
      ctrl.offsetLeft = fixOffset(tab.offsetLeft);
    }

    function previousPage () {
      var i, tab;
      for (i = 0; i < elements.tabs.length; i++) {
        tab = elements.tabs[i];
        if (tab.offsetLeft + tab.offsetWidth >= ctrl.offsetLeft) break;
      }
      ctrl.offsetLeft = fixOffset(tab.offsetLeft + tab.offsetWidth - elements.canvas.clientWidth);
    }

    function canPageBack () {
      return ctrl.offsetLeft > 0;
    }

    function canPageForward () {
      var lastTab = elements.tabs[elements.tabs.length - 1];
      return lastTab && lastTab.offsetLeft + lastTab.offsetWidth > elements.canvas.clientWidth + ctrl.offsetLeft;
    }

    function attachRipple (scope, element) {
      var options = { colorElement: angular.element(elements.inkBar) };
      $mdInkRipple.attachTabBehavior(scope, element, options);
    }
  }
})();<|endoftext|>


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

var express = require('express')
  , mongoStore = require('connect-mongo')(express)
  , flash = require('connect-flash')
  , viewHelpers = require('./middlewares/view')

module.exports = function (app, config, passport) {

  app.set('showStackError', true)
  // should be placed before express.static
  app.use(express.compress({
    filter: function (req, res) {
      console.log(res.getHeader('Content-Type'));
      return /json|text|javascript|css/.test(res.getHeader('Content-Type'));
    },
    level: 9
  }))
  app.use(express.static(config.root + '/public'))
  app.use(express.logger('dev'))

  // set views path, template engine and default layout
  app.set('views', config.root + '/app/views')
  app.set('view engine', 'jade')

  app.configure(function () {
    // dynamic helpers
    app.use(viewHelpers(config))

    // cookieParser should be above session
    app.use(express.cookieParser())

    // bodyParser should be above methodOverride
    app.use(express.bodyParser())
    app.use(express.methodOverride())

    // express/mongo session storage
    app.use(express.session({
      secret: 'noobjs',
      store: new mongoStore({
        url: config.db,
        collection : 'sessions'
      })
    }))

    // connect flash for flash messages
    app.use(flash())

    // use passport session
    app.use(passport.initialize())
    app.use(passport.session())

    app.use(express.favicon())

    // routes should be at the last
    app.use(app.router)

    // assume "not found" in the error msgs
    // is a 404. this is somewhat silly, but
    // valid, you can do whatever you like, set
    // properties, use instanceof etc.
    app.use(function(err, req, res, next){
      // treat as 404
      if (~err.message.indexOf('not found')) return next()

      // log it
      console.error(err.stack)

      // error page
      res.status(500).render('500', { error: err.stack })
    })

    // assume 404 since no middleware responded
    app.use(function(req, res, next){
      res.status(404).render('404', { url: req.originalUrl })
    })

  })
}
<commit_msg>remove console.log<commit_after>
/**
 * Module dependencies.
 */

var express = require('express')
  , mongoStore = require('connect-mongo')(express)
  , flash = require('connect-flash')
  , viewHelpers = require('./middlewares/view')

module.exports = function (app, config, passport) {

  app.set('showStackError', true)
  // should be placed before express.static
  app.use(express.compress({
    filter: function (req, res) {
      return /json|text|javascript|css/.test(res.getHeader('Content-Type'));
    },
    level: 9
  }))
  app.use(express.static(config.root + '/public'))
  app.use(express.logger('dev'))

  // set views path, template engine and default layout
  app.set('views', config.root + '/app/views')
  app.set('view engine', 'jade')

  app.configure(function () {
    // dynamic helpers
    app.use(viewHelpers(config))

    // cookieParser should be above session
    app.use(express.cookieParser())

    // bodyParser should be above methodOverride
    app.use(express.bodyParser())
    app.use(express.methodOverride())

    // express/mongo session storage
    app.use(express.session({
      secret: 'noobjs',
      store: new mongoStore({
        url: config.db,
        collection : 'sessions'
      })
    }))

    // connect flash for flash messages
    app.use(flash())

    // use passport session
    app.use(passport.initialize())
    app.use(passport.session())

    app.use(express.favicon())

    // routes should be at the last
    app.use(app.router)

    // assume "not found" in the error msgs
    // is a 404. this is somewhat silly, but
    // valid, you can do whatever you like, set
    // properties, use instanceof etc.
    app.use(function(err, req, res, next){
      // treat as 404
      if (~err.message.indexOf('not found')) return next()

      // log it
      console.error(err.stack)

      // error page
      res.status(500).render('500', { error: err.stack })
    })

    // assume 404 since no middleware responded
    app.use(function(req, res, next){
      res.status(404).render('404', { url: req.originalUrl })
    })

  })
}
<|endoftext|>


<commit_before>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme
  'firefox-compact-light@mozilla.org@personas.mozilla.org', // Default Compact Light theme
  'firefox-compact-dark@mozilla.org@personas.mozilla.org', // Default Compact Dark theme
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
  'flyweb@mozilla.org', // FlyWeb
  'formautofill@mozilla.org', // Form Autofill
  'presentation@mozilla.org', // Presentation
  'shield-recipe-client@mozilla.org', // Shield Recipe Client
  'webcompat-reporter@mozilla.org', // WebCompat Reporter
  'disableSHA1rollout@mozilla.org', // SHA-1 deprecation staged rollout
  'hsts-priming@mozilla.org', // Send HSTS Priming Requests
  'd3d9fallback@mozilla.org', // D3D9 Acceleration Fallback
  'asyncrendering@mozilla.org', // Asynchronous Plugin Rendering
  'brotli@mozilla.org', // Disable Brotli on Firefox 44, 45
  'diagnostics@mozilla.org', // Diagnose Firefox update problems
  'malware-remediation@mozilla.org', // Youtube Unblocker Remediation
  'outofdate-notifications@mozilla.org', // Firefox out of date notifications
  'websensehelper@mozilla.org', // Websense Helper
  'tls13-compat-ff51@mozilla.org', // TLS 1.3 Compatibility Testing
  'tls13-comparison-all-v1@mozilla.org', // TLS 1.3 A/B Test Experiment
  'deployment-checker@mozilla.org', // Site Deployment Checker
  'screenshots@mozilla.org', // Firefox Screenshots
  'disable-prefetch@mozilla.org', // Disable Prefetch
  'activity-stream@mozilla.org', // Activity Stream
  'disable-cert-transparency@mozilla.org', // Disable TLS Certificate Transparency
  'disable-ocsp-stapling@mozilla.org', // Disable OCSP Stapling
  'onboarding@mozilla.org', // Photon onboarding
  'followonsearch@mozilla.com', // Follow-on Search Telemetry
  'clicktoplay-rollout@mozilla.org', // Click to Play Rollout
];
<commit_msg>new system add-on<commit_after>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme
  'firefox-compact-light@mozilla.org@personas.mozilla.org', // Default Compact Light theme
  'firefox-compact-dark@mozilla.org@personas.mozilla.org', // Default Compact Dark theme
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
  'flyweb@mozilla.org', // FlyWeb
  'formautofill@mozilla.org', // Form Autofill
  'presentation@mozilla.org', // Presentation
  'shield-recipe-client@mozilla.org', // Shield Recipe Client
  'webcompat-reporter@mozilla.org', // WebCompat Reporter
  'disableSHA1rollout@mozilla.org', // SHA-1 deprecation staged rollout
  'hsts-priming@mozilla.org', // Send HSTS Priming Requests
  'd3d9fallback@mozilla.org', // D3D9 Acceleration Fallback
  'asyncrendering@mozilla.org', // Asynchronous Plugin Rendering
  'brotli@mozilla.org', // Disable Brotli on Firefox 44, 45
  'diagnostics@mozilla.org', // Diagnose Firefox update problems
  'malware-remediation@mozilla.org', // Youtube Unblocker Remediation
  'outofdate-notifications@mozilla.org', // Firefox out of date notifications
  'websensehelper@mozilla.org', // Websense Helper
  'tls13-compat-ff51@mozilla.org', // TLS 1.3 Compatibility Testing
  'tls13-comparison-all-v1@mozilla.org', // TLS 1.3 A/B Test Experiment
  'deployment-checker@mozilla.org', // Site Deployment Checker
  'screenshots@mozilla.org', // Firefox Screenshots
  'disable-prefetch@mozilla.org', // Disable Prefetch
  'activity-stream@mozilla.org', // Activity Stream
  'disable-cert-transparency@mozilla.org', // Disable TLS Certificate Transparency
  'disable-ocsp-stapling@mozilla.org', // Disable OCSP Stapling
  'onboarding@mozilla.org', // Photon onboarding
  'followonsearch@mozilla.com', // Follow-on Search Telemetry
  'clicktoplay-rollout@mozilla.org', // Click to Play Rollout
  'tls13-middlebox@mozilla.org', // TLS 1.3 Compatibility Testing of Middleboxes
];
<|endoftext|>


<commit_before>var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    async = require('async');

/**
 * User Schema
 */
var UserSchema = new Schema({
    email: { type: String, required: true }, // 이메일 주소
    pw: { type: String, required: true }, // 패스워드
    //authType: { type: String, required: true }, // 인증타입
    //authKey: { type: String, required: true }, // 인증키
    name: { type: String, required: true }, // 닉네임
    profileUrl: { type: String, default: '' }, // 프로필 이미지 주소
    feeds: { type: Array, default: [] }, // 추가한 사이트 목록
    keywords: { type: Array, default: [] }, // 추가한 키우드 목록
    createDate: { type: Date, required: true }, // 생성 시간
    lastFeedDate: { type: Date, default: new Date() }, // 마지막으로 피드 가져온 시간
    // 클라이언트로 내려주는 데이터를 위한 필드들
    clips: { type: Array }
}, { collection: 'user' });

UserSchema.index({ name: 1 }, { unique: true });

/**
 * Model Methods
 */

UserSchema.statics.getUser = function(criteria, callback) {
    var self = this;

    async.waterfall([
        function(callback) {
            self.findOne(criteria, function(err, user) {
                callback(err, user);
            });
        },
        function(user, callback) {
            self.model('Clip').find({user: criteria._id}, function(err, clips) {
                if (err || user == null) return callback(err);
                user.clips = clips || [];
                callback(null, user);
            });
        }
    ], function (err, user) {
        if (err) return callback(err);
        if (!user) return callback("user is not exist!");
        user.profileUrl = user.profileUrl || "/images/empty_user_icon.png";
        callback(null, user);
    });
};

UserSchema.statics.getUsers = function(criteria, projection, options, callback) {
    this.find(criteria, projection, options, callback);
};

UserSchema.statics.saveUser = function(doc, callback) {

    if (!doc) return;

    doc.createDate = doc.createDate ? doc.createDate : new Date();
    doc.lastFeedDate = new Date("2010-01-01");
    this.create(doc, callback);
};

UserSchema.statics.updateUser = function(conditions, doc, callback) {
    if (!conditions || !doc) return;
    doc.lastFeedDate = new Date("2010-01-01");
    this.update(conditions, doc, callback);
};

UserSchema.statics.deleteUser = function(criteria, callback) {
    if (!criteria) return;

    this.remove(criteria, callback);
};

module.exports = mongoose.model('User', UserSchema);<commit_msg>Update User<commit_after>var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    async = require('async');

/**
 * User Schema
 */
var UserSchema = new Schema({
    email: { type: String, required: true }, // 이메일 주소
    pw: { type: String, required: true }, // 패스워드
    //authType: { type: String, required: true }, // 인증타입
    //authKey: { type: String, required: true }, // 인증키
    name: { type: String, required: true }, // 닉네임
    profileUrl: { type: String, default: '' }, // 프로필 이미지 주소
    feeds: { type: Array, default: [] }, // 추가한 사이트 목록
    keywords: { type: Array, default: [] }, // 추가한 키우드 목록
    createDate: { type: Date, required: true }, // 생성 시간
    lastFeedDate: { type: Date, default: new Date() }, // 마지막으로 피드 가져온 시간
    // 클라이언트로 내려주는 데이터를 위한 필드들
    clips: { type: Array }
}, { collection: 'user' });

UserSchema.index({ name: 1 }, { unique: true });

/**
 * Model Methods
 */

UserSchema.statics.getUser = function(criteria, callback) {
    var self = this;

    async.waterfall([
        function(callback) {
            self.findOne(criteria, function(err, user) {
                callback(err, user);
            });
        },
        function(user, callback) {
            self.model('Clip').find({user: criteria._id}, function(err, clips) {
                if (err || user == null) return callback(err);
                user.clips = clips || [];
                callback(null, user);
            });
        }
    ], function (err, user) {
        if (err) return callback(err);
        if (!user) return callback("user is not exist!");
        user.profileUrl = user.profileUrl || "/images/empty_user_icon.png";
        callback(null, user);
    });
};

UserSchema.statics.getUsers = function(criteria, projection, options, callback) {
    this.find(criteria, projection, options, callback);
};

UserSchema.statics.saveUser = function(doc, callback) {

    if (!doc) return;

    doc.createDate = doc.createDate ? doc.createDate : new Date();
    doc.lastFeedDate = new Date("2010-01-01");
    this.create(doc, callback);
};

UserSchema.statics.updateUser = function(conditions, doc, callback) {
    if (!conditions || !doc) return;
    //doc.lastFeedDate = new Date("2010-01-01");
    this.update(conditions, doc, callback);
};

UserSchema.statics.deleteUser = function(criteria, callback) {
    if (!criteria) return;

    this.remove(criteria, callback);
};

module.exports = mongoose.model('User', UserSchema);<|endoftext|>


<commit_before>// test/queryController.tests.js
var assert = require('assert'),
  express = require('express'),
  app = express(),
  request = require('supertest'),
  proxyquire = require('proxyquire').noPreserveCache(),
  eventStoreStub = function() {
    this.streams = {
      get: function(args, callback) {
        callback(null, {
          statusCode: '404',
          body: ''
        });
      }
    }
  },
  controller = proxyquire('../../api/queryController', {
    'eventstore-client': eventStoreStub
  });

controller.init(app);

describe('queryController', function() {
  describe('when I issue a workitem query for an asset that has no associated commits', function() {
    var esStub = function() {
      this.streams = {
        get: function(args, callback) {
          callback(null, {
            statusCode: '404',
            body: ''
          });
        }
      }
    };

    controller = proxyquire('../../api/queryController', {
      'eventstore-client': esStub
    });

    it('returns a 200 OK response with an empty commits array', function(done) {
      //exercise our api
      request(app)
        .get('/api/query?workitem=123&pageSize=5')
        .end(function(err, res) {
          assert.equal(err, null);
          assert.equal(res.statusCode, 200);
          assert.deepEqual(res.body.commits, []);
          done();
        });
    });
  });

  describe('when I issue a query without a workitem as a parameter', function() {
    controller = proxyquire('../../api/queryController', {
      'eventstore-client': {}
    });

    it('returns a 400 Bad Request response with a error message', function(done) {
      request(app)
        .get('/api/query')
        .end(function(err, res) {
          assert.equal(err, null);
          assert.equal(res.statusCode, 400);
          assert.equal(res.body.error, 'Parameter workitem is required');
          done();
        });
    });
  });
});<commit_msg>S-49992 some cleaning.<commit_after>// test/queryController.tests.js
var assert = require('assert'),
  express = require('express'),
  app = express(),
  request = require('supertest'),
  proxyquire = require('proxyquire').noPreserveCache();

describe('queryController', function() {
  describe('when I issue a workitem query for an asset that has no associated commits', function() {
    var esStub = function() {
      this.streams = {
        get: function(args, callback) {
          callback(null, {
            statusCode: '404',
            body: ''
          });
        }
      }
    };

    controller = proxyquire('../../api/queryController', {
      'eventstore-client': esStub
    });

    controller.init(app);

    it('returns a 200 OK response with an empty commits array', function(done) {
      //exercise our api
      request(app)
        .get('/api/query?workitem=123&pageSize=5')
        .end(function(err, res) {
          assert.equal(err, null);
          assert.equal(res.statusCode, 200);
          assert.deepEqual(res.body.commits, []);
          done();
        });
    });
  });

  describe('when I issue a query without a workitem as a parameter', function() {
    controller = proxyquire('../../api/queryController', {
      'eventstore-client': {}
    });

    controller.init(app);

    it('returns a 400 Bad Request response with a error message', function(done) {
      request(app)
        .get('/api/query')
        .end(function(err, res) {
          assert.equal(err, null);
          assert.equal(res.statusCode, 400);
          assert.equal(res.body.error, 'Parameter workitem is required');
          done();
        });
    });
  });
});<|endoftext|>


<commit_before>/* global describe, it */
'use strict';

require('co-mocha');

let exec    = require('child_process').exec;
let chai    = require('chai');
let axios   = require('axios');
let service = require('..');
let expect  = chai.expect;

chai.use(require('chai-as-promised'));

describe('express-micro-service', function() {
  it('exposes methods via post', function*() {
    let server = yield start('echoing-service');
    let request = server.post('/echo', { some: 'data' });

    return expect(request)
      .to.eventually.be.fulfilled
      .then((res) => {
        expect(res.data).to.deep.equal({ success: true, echoed: { some: 'data' }});
        server.kill();
      });
  });

  it('returns 400 for known errors', function*() {
    let server = yield start('known-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(400);
          expect(res.data).to.deep.equal({ error: { name: 'SomeKnownError', message: 'an error message' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });

  it('returns 500 for unknown errors', function*() {
    let server = yield start('unkown-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(500);
          expect(res.data).to.deep.equal({ error: { name: 'Error', message: 'An unexpected error occurred.' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });

  it('supports multiple return values', function*() {
    let server = yield start('multiple-return-values-service');
    let request = server.post('/brothers');

    return expect(request)
      .to.eventually.be.fulfilled
      .then((res) => {
        expect(res.data).to.deep.equal({ success: true, max: 'my name is max', julian: 'my name is julian' });
        server.kill();
      });
  });

  it('crashes on unkown errors', function(done) {
    start('unkown-error-service')
      .then(function(server) {
        server.on('exit', (code) => {
          expect(code).to.equal(1);
          done();
        });

        return server.post('/erroring').catch(()=>{});
      })
      .catch(done);
  });

  it('returns 500 for unexpected http errors', function*() {
    let server = yield start('unkown-http-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(500);
          expect(res.data).to.deep.equal({ error: { name: 'Error', message: 'An unexpected error occurred.' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });
});

let port = 3333;

function start(service) {
  return (function(port) {
    let started = false;

    return new Promise((resolve, reject) => {
      let p = exec('SERVICE_PORT=' + port + ' node ' + __dirname + '/fixtures/' + service + '.js');

      p.stdout.on('data', function(data) {
        if (!started && data.indexOf('Listening') !== -1) {
          started = true;

          p.post = function(method, data) {
            return axios.post('http://localhost:' + port + method, data);
          };

          resolve(p);
        }
      });

      p.stderr.on('data', function(data) {
        if (!started) {
          reject(data);
        }
      });

      process.on('exit', () => p.kill());
    });
  })(++port);
}<commit_msg>wait for processes to exit before starting new test<commit_after>/* global describe, it */
'use strict';

require('co-mocha');

let exec    = require('child_process').exec;
let chai    = require('chai');
let axios   = require('axios');
let service = require('..');
let expect  = chai.expect;

chai.use(require('chai-as-promised'));

describe('express-micro-service', function() {
  it('exposes methods via post', function*() {
    let server = yield start('echoing-service');
    let request = server.post('/echo', { some: 'data' });

    return expect(request)
      .to.eventually.be.fulfilled
      .then((res) => {
        expect(res.data).to.deep.equal({ success: true, echoed: { some: 'data' }});
        return server.kill();
      });
  });

  it('returns 400 for known errors', function*() {
    let server = yield start('known-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(400);
          expect(res.data).to.deep.equal({ error: { name: 'SomeKnownError', message: 'an error message' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });

  it('returns 500 for unknown errors', function*() {
    let server = yield start('unkown-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(500);
          expect(res.data).to.deep.equal({ error: { name: 'Error', message: 'An unexpected error occurred.' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });

  it('supports multiple return values', function*() {
    let server = yield start('multiple-return-values-service');
    let request = server.post('/brothers');

    return expect(request)
      .to.eventually.be.fulfilled
      .then((res) => {
        expect(res.data).to.deep.equal({ success: true, max: 'my name is max', julian: 'my name is julian' });
        return server.kill();
      });
  });

  it('crashes on unkown errors', function(done) {
    start('unkown-error-service')
      .then(function(server) {
        server.on('exit', (code) => {
          expect(code).to.equal(1);
          done();
        });

        return server.post('/erroring').catch(()=>{});
      })
      .catch(done);
  });

  it('returns 500 for unexpected http errors', function*() {
    let server = yield start('unkown-http-error-service');
    let request = server.post('/erroring');

    return Promise
      .all([
        request.catch((res) => {
          expect(res.status).to.equal(500);
          expect(res.data).to.deep.equal({ error: { name: 'Error', message: 'An unexpected error occurred.' }});
        }),
        expect(request).to.eventually.be.rejected
      ])
      .then(() => server.kill());
  });
});

let port = 3333;

function start(service) {
  return (function(port) {
    let started = false;

    return new Promise((resolve, reject) => {
      let p = exec('SERVICE_PORT=' + port + ' node ' + __dirname + '/fixtures/' + service + '.js');

      p.stdout.on('data', function(data) {
        if (!started && data.indexOf('Listening') !== -1) {
          started = true;

          p.post = function(method, data) {
            return axios.post('http://localhost:' + port + method, data);
          };

          let kill = p.kill.bind(p);
          p.kill = function() {
            kill();

            return new Promise((resolve, reject) => {
              p.on('exit', () => resolve());
            });
          };

          resolve(p);
        }
      });

      p.stderr.on('data', function(data) {
        if (!started) {
          reject(data);
        }
      });

      process.on('exit', () => p.kill());
    });
  })(port++);
}<|endoftext|>


<commit_before>array = [].constructor;

function toJson(obj, pretty){
  var buf = [];
  toJsonArray(buf, obj, pretty ? "\n  " : null, []);
  return buf.join('');
}

function toPrettyJson(obj)  {
  return toJson(obj, true);
}

function fromJson(json) {
  if (!json) return json;
  try {
    var parser = new Parser(json, true);
    var expression =  parser.primary();
    parser.assertAllConsumed();
    return expression();
  } catch (e) {
    error("fromJson error: ", json, e);
    throw e;
  }
}

angular['toJson'] = toJson;
angular['fromJson'] = fromJson;

function toJsonArray(buf, obj, pretty, stack){
  if (typeof obj == "object") {
    if (includes(stack, obj)) {
      buf.push("RECURSION");
      return;
    }
    stack.push(obj);
  }
  var type = typeof obj;
  if (obj === null) {
    buf.push("null");
  } else if (type === 'function') {
    return;
  } else if (type === 'boolean') {
    buf.push('' + obj);
  } else if (type === 'number') {
    if (isNaN(obj)) {
      buf.push('null');
    } else {
      buf.push('' + obj);
    }
  } else if (type === 'string') {
    return buf.push(angular['String']['quoteUnicode'](obj));
  } else if (type === 'object') {
    if (obj instanceof Array) {
      buf.push("[");
      var len = obj.length;
      var sep = false;
      for(var i=0; i<len; i++) {
        var item = obj[i];
        if (sep) buf.push(",");
        if (typeof item == 'function' || typeof item == 'undefined') {
          buf.push("null");
        } else {
          toJsonArray(buf, item, pretty, stack);
        }
        sep = true;
      }
      buf.push("]");
    } else if (obj instanceof Date) {
      buf.push(angular['String']['quoteUnicode'](angular['Date']['toString'](obj)));
    } else {
      buf.push("{");
      if (pretty) buf.push(pretty);
      var comma = false;
      var childPretty = pretty ? pretty + "  " : false;
      var keys = [];
      for(var k in obj) {
        if (!obj.hasOwnProperty(k) || k.indexOf('$$') === 0 || obj[k] === undefined)
          continue;
        keys.push(k);
      }
      keys.sort();
      for ( var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
        var key = keys[keyIndex];
        try {
          var value = obj[key];
          if (typeof value != 'function') {
            if (comma) {
              buf.push(",");
              if (pretty) buf.push(pretty);
            }
            buf.push(angular['String']['quote'](key));
            buf.push(":");
            toJsonArray(buf, value, childPretty, stack);
            comma = true;
          }
        } catch (e) {
        }
      }
      buf.push("}");
    }
  }
  if (typeof obj == "object") {
    stack.pop();
  }
}
<commit_msg>removing useless catch that causes troubles when FF throws exceptions within the loop but outside of the try/catch clause<commit_after>array = [].constructor;

function toJson(obj, pretty){
  var buf = [];
  toJsonArray(buf, obj, pretty ? "\n  " : null, []);
  return buf.join('');
}

function toPrettyJson(obj)  {
  return toJson(obj, true);
}

function fromJson(json) {
  if (!json) return json;
  try {
    var parser = new Parser(json, true);
    var expression =  parser.primary();
    parser.assertAllConsumed();
    return expression();
  } catch (e) {
    error("fromJson error: ", json, e);
    throw e;
  }
}

angular['toJson'] = toJson;
angular['fromJson'] = fromJson;

function toJsonArray(buf, obj, pretty, stack){
  if (typeof obj == "object") {
    if (includes(stack, obj)) {
      buf.push("RECURSION");
      return;
    }
    stack.push(obj);
  }
  var type = typeof obj;
  if (obj === null) {
    buf.push("null");
  } else if (type === 'function') {
    return;
  } else if (type === 'boolean') {
    buf.push('' + obj);
  } else if (type === 'number') {
    if (isNaN(obj)) {
      buf.push('null');
    } else {
      buf.push('' + obj);
    }
  } else if (type === 'string') {
    return buf.push(angular['String']['quoteUnicode'](obj));
  } else if (type === 'object') {
    if (obj instanceof Array) {
      buf.push("[");
      var len = obj.length;
      var sep = false;
      for(var i=0; i<len; i++) {
        var item = obj[i];
        if (sep) buf.push(",");
        if (typeof item == 'function' || typeof item == 'undefined') {
          buf.push("null");
        } else {
          toJsonArray(buf, item, pretty, stack);
        }
        sep = true;
      }
      buf.push("]");
    } else if (obj instanceof Date) {
      buf.push(angular['String']['quoteUnicode'](angular['Date']['toString'](obj)));
    } else {
      buf.push("{");
      if (pretty) buf.push(pretty);
      var comma = false;
      var childPretty = pretty ? pretty + "  " : false;
      var keys = [];
      for(var k in obj) {
        if (!obj.hasOwnProperty(k) || k.indexOf('$$') === 0 || obj[k] === undefined)
          continue;
        keys.push(k);
      }
      keys.sort();
      for ( var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
        var key = keys[keyIndex];
        var value = obj[key];
        if (typeof value != 'function') {
          if (comma) {
            buf.push(",");
            if (pretty) buf.push(pretty);
          }
          buf.push(angular['String']['quote'](key));
          buf.push(":");
          toJsonArray(buf, value, childPretty, stack);
          comma = true;
        }
      }
      buf.push("}");
    }
  }
  if (typeof obj == "object") {
    stack.pop();
  }
}
<|endoftext|>


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

module.exports = mongoose.model('Todo', {
    text: {
        type: String,
        default: ''
    },
    text1: {
        type: String,
        default: ''
    }
});<commit_msg>Update todo.js<commit_after>var mongoose = require('mongoose');

module.exports = mongoose.model('Todo', {
    text: {
        type: String,
        default: ''
    }
});
<|endoftext|>


<commit_before>/* global process */
/* jslint node: true */
var fs = require('fs');
var md5 = require('md5');
var replace = require("replace");

function updateAppConfig() {
  var baseURL = process.env.Exceptionless_BaseURL ? process.env.Exceptionless_BaseURL : 'http://localhost:50000';
  var exceptionlessApiKey = process.env.Exceptionless_ApiKey ? process.env.Exceptionless_ApiKey : '';
  var exceptionlessServerUrl = process.env.Exceptionless_ServerUrl ? process.env.Exceptionless_ServerUrl : '';
  var facebookAppId = process.env.Exceptionless_FacebookAppId ? process.env.Exceptionless_FacebookAppId : '';
  var gitHubAppId = process.env.Exceptionless_GitHubAppId ? process.env.Exceptionless_GitHubAppId : '';
  var googleAppId = process.env.Exceptionless_GoogleAppId ? process.env.Exceptionless_GoogleAppId : '';
  var intercomId = process.env.Exceptionless_IntercomAppId ? process.env.Exceptionless_IntercomAppId : '';
  var liveAppId = process.env.Exceptionless_MicrosoftAppId ? process.env.Exceptionless_MicrosoftAppId : '';
  var slackAppId = process.env.Exceptionless_SlackAppId ? process.env.Exceptionless_SlackAppId : '';
  var stripePubKey = process.env.Exceptionless_StripePublishableApiKey ? process.env.Exceptionless_StripePublishableApiKey : '';
  var notificationMessage = process.env.Exceptionless_Message ? process.env.Exceptionless_Message : '';
  var useHTML5Mode = process.env.Exceptionless_HTML5Mode ? process.env.Exceptionless_HTML5Mode === 'true' : false;
  var useSSL = process.env.Exceptionless_EnableSSL ? process.env.Exceptionless_EnableSSL === 'true' : false;
  var enableAccountCreation = process.env.Exceptionless_EnableAccountCreation ? process.env.Exceptionless_EnableAccountCreation === 'true' : true;

  var content = [
    '(function () {',
    '  \'use strict\';',
    '',
    '  angular.module("app.config", [])',
    '    .constant("BASE_URL", "' + baseURL + '")',
    '    .constant("EXCEPTIONLESS_API_KEY", "' + exceptionlessApiKey + '")',
    '    .constant("EXCEPTIONLESS_SERVER_URL", "' + exceptionlessServerUrl + '")',
    '    .constant("FACEBOOK_APPID", "' + facebookAppId + '")',
    '    .constant("GITHUB_APPID", "' + gitHubAppId + '")',
    '    .constant("GOOGLE_APPID", "' + googleAppId + '")',
    '    .constant("INTERCOM_APPID", "' + intercomId + '")',
    '    .constant("LIVE_APPID", "' + liveAppId + '")',
    '    .constant("SLACK_APPID", "' + slackAppId + '")',
    '    .constant("STRIPE_PUBLISHABLE_KEY", "' + stripePubKey + '")',
    '    .constant("SYSTEM_NOTIFICATION_MESSAGE", "' + notificationMessage + '")',
    '    .constant("USE_HTML5_MODE", ' + useHTML5Mode + ')',
    '    .constant("USE_SSL", ' + useSSL + ');',
    '    .constant("ENABLE_ACCOUNT_CREATION", "' + enableAccountCreation + '")',
    '}());'
  ].join('\n');

  var hash = md5(content);

// todo: use cache buster in name
  var configFile = 'app.config.' + hash + '.js';

  fs.writeFile('../../../../' + configFile, content, function (err) {
    if (err)
      throw err;

    console.log('Config generated.');
  });

  replace({
    regex: "app\.config\.*\.js",
    replacement: configFile,
    paths: ['../../../../index.html'],
    recursive: false,
    silent: false
  });
}

function installGoogleTagManager() {
  var googleTagManagerId = process.env.Exceptionless_GoogleTagManagerId ? process.env.Exceptionless_GoogleTagManagerId : '';
  var content = [
    '',
    ""
  ].join('');

  if (!googleTagManagerId) {
    content = '';
  }

  replace({
    regex: '<google-tag-manager><\/google-tag-manager>',
    replacement: content,
    paths: ['../../../../index.html'],
    recursive: false,
    silent: false
  });
}

updateAppConfig();
installGoogleTagManager();
<commit_msg>Fixed build configuration<commit_after>/* global process */
/* jslint node: true */
var fs = require('fs');
var md5 = require('md5');
var replace = require("replace");

function updateAppConfig() {
  var baseURL = process.env.Exceptionless_BaseURL ? process.env.Exceptionless_BaseURL : 'http://localhost:50000';
  var exceptionlessApiKey = process.env.Exceptionless_ApiKey ? process.env.Exceptionless_ApiKey : '';
  var exceptionlessServerUrl = process.env.Exceptionless_ServerUrl ? process.env.Exceptionless_ServerUrl : '';
  var facebookAppId = process.env.Exceptionless_FacebookAppId ? process.env.Exceptionless_FacebookAppId : '';
  var gitHubAppId = process.env.Exceptionless_GitHubAppId ? process.env.Exceptionless_GitHubAppId : '';
  var googleAppId = process.env.Exceptionless_GoogleAppId ? process.env.Exceptionless_GoogleAppId : '';
  var intercomId = process.env.Exceptionless_IntercomAppId ? process.env.Exceptionless_IntercomAppId : '';
  var liveAppId = process.env.Exceptionless_MicrosoftAppId ? process.env.Exceptionless_MicrosoftAppId : '';
  var slackAppId = process.env.Exceptionless_SlackAppId ? process.env.Exceptionless_SlackAppId : '';
  var stripePubKey = process.env.Exceptionless_StripePublishableApiKey ? process.env.Exceptionless_StripePublishableApiKey : '';
  var notificationMessage = process.env.Exceptionless_Message ? process.env.Exceptionless_Message : '';
  var useHTML5Mode = process.env.Exceptionless_HTML5Mode ? process.env.Exceptionless_HTML5Mode === 'true' : false;
  var useSSL = process.env.Exceptionless_EnableSSL ? process.env.Exceptionless_EnableSSL === 'true' : false;
  var enableAccountCreation = process.env.Exceptionless_EnableAccountCreation ? process.env.Exceptionless_EnableAccountCreation === 'true' : true;

  var content = [
    '(function () {',
    '  \'use strict\';',
    '',
    '  angular.module("app.config", [])',
    '    .constant("BASE_URL", "' + baseURL + '")',
    '    .constant("EXCEPTIONLESS_API_KEY", "' + exceptionlessApiKey + '")',
    '    .constant("EXCEPTIONLESS_SERVER_URL", "' + exceptionlessServerUrl + '")',
    '    .constant("FACEBOOK_APPID", "' + facebookAppId + '")',
    '    .constant("GITHUB_APPID", "' + gitHubAppId + '")',
    '    .constant("GOOGLE_APPID", "' + googleAppId + '")',
    '    .constant("INTERCOM_APPID", "' + intercomId + '")',
    '    .constant("LIVE_APPID", "' + liveAppId + '")',
    '    .constant("SLACK_APPID", "' + slackAppId + '")',
    '    .constant("STRIPE_PUBLISHABLE_KEY", "' + stripePubKey + '")',
    '    .constant("SYSTEM_NOTIFICATION_MESSAGE", "' + notificationMessage + '")',
    '    .constant("USE_HTML5_MODE", ' + useHTML5Mode + ')',
    '    .constant("USE_SSL", ' + useSSL + ')',
    '    .constant("ENABLE_ACCOUNT_CREATION", "' + enableAccountCreation + '");',
    '}());'
  ].join('\n');

  var hash = md5(content);

// todo: use cache buster in name
  var configFile = 'app.config.' + hash + '.js';

  fs.writeFile('../../../../' + configFile, content, function (err) {
    if (err)
      throw err;

    console.log('Config generated.');
  });

  replace({
    regex: "app\.config\.*\.js",
    replacement: configFile,
    paths: ['../../../../index.html'],
    recursive: false,
    silent: false
  });
}

function installGoogleTagManager() {
  var googleTagManagerId = process.env.Exceptionless_GoogleTagManagerId ? process.env.Exceptionless_GoogleTagManagerId : '';
  var content = [
    '',
    ""
  ].join('');

  if (!googleTagManagerId) {
    content = '';
  }

  replace({
    regex: '<google-tag-manager><\/google-tag-manager>',
    replacement: content,
    paths: ['../../../../index.html'],
    recursive: false,
    silent: false
  });
}

updateAppConfig();
installGoogleTagManager();
<|endoftext|>


<commit_before>'use strict';

const util = require('util');
const TransportStream = require('./');
const LEVEL = Symbol.for('level');

/**
 * Constructor function for the LegacyTransportStream. This is an internal wrapper
 * `winston >= 3` uses to wrap older transports implementing log(level, message, meta).
 *
 * @param  {Object} opts Options for this TransportStream instance.
 *   @param {Transpot} opts.transport winston@2 or older Transport to wrap.
 */
var LegacyTransportStream = module.exports = function LegacyTransportStream(opts) {
  opts = opts || {};
  if (!opts.transport || typeof opts.transport.log !== 'function') {
    throw new Error('Invalid transport, must be an object with a log method.');
  }

  TransportStream.call(this, opts);

  var self = this;
  this.transport = opts.transport;
  this.level = this.level || opts.transport.level;
  this.handleExceptions = this.handleExceptions || opts.transport.handleExceptions;

  // Display our deprecation notice.
  this._deprecated();

  //
  // Properly bubble up errors from the transport to the LegacyTransportStream
  // instance, but only once no matter how many times this transport is shared.
  //
  function transportError(err) {
    self.emit('error', err, self.transport);
  }

  if (!this.transport.__winstonError) {
    this.transport.__winstonError = transportError;
    this.transport.on('error', this.transport.__winstonError);
  }
};

util.inherits(LegacyTransportStream, TransportStream);

/*
 * @private function _write(info)
 * Writes the info object to our transport instance.
 */
LegacyTransportStream.prototype._write = function (info, enc, callback) {
  if (this.silent || (info.exception === true && !this.handleExceptions)) {
    return callback(null);
  }

  //
  // Remark: This has to be handled in the base transport now because we cannot
  // conditionally write to our pipe targets as stream.
  //
  if (!this.level || this.levels[this.level] >= this.levels[info[LEVEL]]) {
    this.transport.log(info[LEVEL], info.message, info, this._nop);
  }

  callback(null);
};

/*
 * @private function _writev(chunks, callback)
 * Writes the batch of info objects (i.e. "object chunks") to our transport instance
 * after performing any necessary filtering.
 */
LegacyTransportStream.prototype._writev = function (chunks, callback) {
  const infos = chunks.filter(this._accept, this);
  if (!infos.length) {
    return callback(null);
  }

  for (var i = 0; i < infos.length; i++) {
    this.transport.log(infos[i].chunk[LEVEL], infos[i].chunk.message, infos[i].chunk, this._nop);
    infos[i].callback();
  }

  return callback(null);
};

/**
 * Displays a deprecation notice. Defined as a function so it can be overriden in tests.
 */
LegacyTransportStream.prototype._deprecated = function () {
  console.error([
    `${this.transport.name} is a legacy winston transport. Consider upgrading: `,
    '- Upgrade docs: https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md'
  ].join('\n'));
};

/*
 * Clean up error handling state on the legacy transport associated
 * with this instance.
 */
LegacyTransportStream.prototype.close = function () {
  if (this.transport.close) {
    this.transport.close();
  }

  if (this.transport.__winstonError) {
    this.transport.removeListener('error', this.transport.__winstonError);
    this.transport.__winstonError = null;
  }
};
<commit_msg>[refactor] Do not make a copy of the infos Array in `LegacyTransportStream.prototype._writev`<commit_after>'use strict';

const util = require('util');
const TransportStream = require('./');
const LEVEL = Symbol.for('level');

/**
 * Constructor function for the LegacyTransportStream. This is an internal wrapper
 * `winston >= 3` uses to wrap older transports implementing log(level, message, meta).
 *
 * @param  {Object} opts Options for this TransportStream instance.
 *   @param {Transpot} opts.transport winston@2 or older Transport to wrap.
 */
var LegacyTransportStream = module.exports = function LegacyTransportStream(opts) {
  opts = opts || {};
  if (!opts.transport || typeof opts.transport.log !== 'function') {
    throw new Error('Invalid transport, must be an object with a log method.');
  }

  TransportStream.call(this, opts);

  var self = this;
  this.transport = opts.transport;
  this.level = this.level || opts.transport.level;
  this.handleExceptions = this.handleExceptions || opts.transport.handleExceptions;

  // Display our deprecation notice.
  this._deprecated();

  //
  // Properly bubble up errors from the transport to the LegacyTransportStream
  // instance, but only once no matter how many times this transport is shared.
  //
  function transportError(err) {
    self.emit('error', err, self.transport);
  }

  if (!this.transport.__winstonError) {
    this.transport.__winstonError = transportError;
    this.transport.on('error', this.transport.__winstonError);
  }
};

util.inherits(LegacyTransportStream, TransportStream);

/*
 * @private function _write(info)
 * Writes the info object to our transport instance.
 */
LegacyTransportStream.prototype._write = function (info, enc, callback) {
  if (this.silent || (info.exception === true && !this.handleExceptions)) {
    return callback(null);
  }

  //
  // Remark: This has to be handled in the base transport now because we cannot
  // conditionally write to our pipe targets as stream.
  //
  if (!this.level || this.levels[this.level] >= this.levels[info[LEVEL]]) {
    this.transport.log(info[LEVEL], info.message, info, this._nop);
  }

  callback(null);
};

/*
 * @private function _writev(chunks, callback)
 * Writes the batch of info objects (i.e. "object chunks") to our transport instance
 * after performing any necessary filtering.
 */
LegacyTransportStream.prototype._writev = function (chunks, callback) {
  for (var i = 0; i < chunks.length; i++) {
    if (this._accept(chunks[i])) {
      this.transport.log(chunks[i].chunk[LEVEL], chunks[i].chunk.message, chunks[i].chunk, chunks[i].callback);
    }
  }

  return callback(null);
};

/**
 * Displays a deprecation notice. Defined as a function so it can be overriden in tests.
 */
LegacyTransportStream.prototype._deprecated = function () {
  console.error([
    `${this.transport.name} is a legacy winston transport. Consider upgrading: `,
    '- Upgrade docs: https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md'
  ].join('\n'));
};

/*
 * Clean up error handling state on the legacy transport associated
 * with this instance.
 */
LegacyTransportStream.prototype.close = function () {
  if (this.transport.close) {
    this.transport.close();
  }

  if (this.transport.__winstonError) {
    this.transport.removeListener('error', this.transport.__winstonError);
    this.transport.__winstonError = null;
  }
};
<|endoftext|>


<commit_before>var acorn = require('acorn'),
  walk = require('acorn/util/walk.js'),
  fs = require('fs');

var ast;

module.exports = function (filename, cb) {

  fs.readFile(filename, 'utf8', function (err, input) {
    if (err) {
      cb(err);
      return;
    }
    var options = {
      strictSemicolons: true
    };
    ast = acorn.parse(input, options);
    var functions = {

      WhileStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      ForInStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      ForStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      IfStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.consequent, state);
        var consequentEnd = state.previous;
        state.previous = [];
        fillNode(node, state);
        if (node.alternate !== null) {
          c(node.alternate, state);
        }
        state.previous = state.previous.concat(consequentEnd);
      },

      ExpressionStatement: function (node, state, c) {
        fillNode(node, state);
        expressionHandler(node.expression, node);
      },

      VariableDeclaration: function (node, state, c) {
        fillNode(node, state);
      },

      FunctionDeclaration: function(node, state, c) {
        var previous = state.previous;
        state.previous = [];
        c(node.body, state);
        state.previous = previous;
        fillNode(node, state);
      }
    };
    walk.recursive(ast, {}, functions);
    cb(null, ast);
  });
};

function fillNode(node, state) {
  node.previous = node.previous || [];
  node.next = node.next || [];
  state.previous = state.previous || [];

  state.previous.forEach(function (previous) {
    if (previous !== undefined) {
      node.previous.push(previous);
    }
  });
  state.previous = [node];

  node.previous.forEach(function (previous) {
    previous.next = previous.next || [];
    if (previous.next.indexOf(node) === -1) {
      previous.next.push(node);
    }
  });

}

function expressionHandler(expression, statement) {
  switch (expression.type) {
    case 'ArrayExpression':
      for (var i = 0; i < expression.elements.length; i++) {
        if (expression.elements[i] !== null) {
          expressionHandler(expression.elements[i], statement);
        }
      };
      expression.evaluate = function() {
        var a = [];
        for (var i = 0; i < expression.elements.length; i++) {
          if (expression.elements[i] !== null) {
            a.push(expression.elements[i].evaluate());
          } else {
            a.push(expression.elements[i]);
          }
        }
        return a;
      };
      expression.isUserControlled = function() {
        for (var i = expression.elements.length - 1; i >= 0; i--) {
          if(expression.elements[i] !== null && expression.elements[i].isUserControlled()) {
            return true;
          }
        }
        return false;
      };
      break;
    case 'BinaryExpression':
      expressionHandler(expression.right, statement);
      expressionHandler(expression.left, statement);
      expression.evaluate = function() {
        var left = expression.left.evaluate();
        var right = expression.right.evaluate();
        if (typeof left === 'string') {
          left = '\'' + left + '\'';
        }
        if (typeof right === 'string') {
          right = '\'' + right + '\'';
        }
        var result = eval(left + ' ' + expression.operator + ' ' + right);
        return result;
      };
      expression.isUserControlled = function() {
        return left.isUserControlled() || right.isUserControlled();
      };
      break;
    case 'CallExpression':
      for (var i = 0; i < expression.arguments.length; i++) {
        expressionHandler(expression.arguments[i], statement);
      };
      expression.evaluate = function() {
        return undefined; // TODO implement
      };
      expression.isUserControlled = function() {
        return true; // TODO implement
      };
      break;
    case 'Identifier':
      expression.evaluate = function() {
        return expression.name; // TODO something like return context[expression.name]
      };
      expression.isUserControlled = function() {
        return false;
      };
      break;
    case 'Literal':
      expression.evaluate = function() {
        return expression.value;
      };
      expression.isUserControlled = function() {
        return false;
      };
      break;
    default:
      expression.evaluate = function() {
        return undefined;
      };
      expression.isUserControlled = function() {
        // we don't know, so to be sure we say yes
        return true;
      };
      break;
  }
}
<commit_msg>added empty expression type cases<commit_after>var acorn = require('acorn'),
  walk = require('acorn/util/walk.js'),
  fs = require('fs');

var ast;

module.exports = function (filename, cb) {

  fs.readFile(filename, 'utf8', function (err, input) {
    if (err) {
      cb(err);
      return;
    }
    var options = {
      strictSemicolons: true
    };
    ast = acorn.parse(input, options);
    var functions = {

      WhileStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      ForInStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      ForStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.body, state);
        fillNode(node, state);
      },

      IfStatement: function (node, state, c) {
        fillNode(node, state);
        c(node.consequent, state);
        var consequentEnd = state.previous;
        state.previous = [];
        fillNode(node, state);
        if (node.alternate !== null) {
          c(node.alternate, state);
        }
        state.previous = state.previous.concat(consequentEnd);
      },

      ExpressionStatement: function (node, state, c) {
        fillNode(node, state);
        expressionHandler(node.expression, node);
      },

      VariableDeclaration: function (node, state, c) {
        fillNode(node, state);
      },

      FunctionDeclaration: function(node, state, c) {
        var previous = state.previous;
        state.previous = [];
        c(node.body, state);
        state.previous = previous;
        fillNode(node, state);
      }
    };
    walk.recursive(ast, {}, functions);
    cb(null, ast);
  });
};

function fillNode(node, state) {
  node.previous = node.previous || [];
  node.next = node.next || [];
  state.previous = state.previous || [];

  state.previous.forEach(function (previous) {
    if (previous !== undefined) {
      node.previous.push(previous);
    }
  });
  state.previous = [node];

  node.previous.forEach(function (previous) {
    previous.next = previous.next || [];
    if (previous.next.indexOf(node) === -1) {
      previous.next.push(node);
    }
  });

}

function expressionHandler(expression, statement) {
  switch (expression.type) {
    case 'ArrowExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'ArrayExpression':
      for (var i = 0; i < expression.elements.length; i++) {
        if (expression.elements[i] !== null) {
          expressionHandler(expression.elements[i], statement);
        }
      };
      expression.evaluate = function() {
        var a = [];
        for (var i = 0; i < expression.elements.length; i++) {
          if (expression.elements[i] !== null) {
            a.push(expression.elements[i].evaluate());
          } else {
            a.push(expression.elements[i]);
          }
        }
        return a;
      };
      expression.isUserControlled = function() {
        for (var i = expression.elements.length - 1; i >= 0; i--) {
          if(expression.elements[i] !== null && expression.elements[i].isUserControlled()) {
            return true;
          }
        }
        return false;
      };
      break;
    case 'AssignmentExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'BinaryExpression':
      expressionHandler(expression.right, statement);
      expressionHandler(expression.left, statement);
      expression.evaluate = function() {
        var left = expression.left.evaluate();
        var right = expression.right.evaluate();
        if (typeof left === 'string') {
          left = '\'' + left + '\'';
        }
        if (typeof right === 'string') {
          right = '\'' + right + '\'';
        }
        var result = eval(left + ' ' + expression.operator + ' ' + right);
        return result;
      };
      expression.isUserControlled = function() {
        return left.isUserControlled() || right.isUserControlled();
      };
      break;
    case 'CallExpression':
      for (var i = 0; i < expression.arguments.length; i++) {
        expressionHandler(expression.arguments[i], statement);
      };
      expression.evaluate = function() {
        return undefined; // TODO implement
      };
      expression.isUserControlled = function() {
        return true; // TODO implement
      };
      break;
    case 'ConditionalExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'FunctionExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'Identifier':
      expression.evaluate = function() {
        return expression.name; // TODO something like return context[expression.name]
      };
      expression.isUserControlled = function() {
        return false;
      };
      break;
    case 'Literal':
      expression.evaluate = function() {
        return expression.value;
      };
      expression.isUserControlled = function() {
        return false;
      };
      break;
    case 'LogicalExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'MemberExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'NewExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'ObjectExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'SequenceExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'ThisExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'UnaryExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    case 'UpdateExpression':
      // TODO expressionHandler(, statement);
      expression.evaluate = function() {
        // TODO implement
        return undefined;
      };
      expression.isUserControlled = function() {
        // TODO implement
        return false;
      };
      break;
    default:
      expression.evaluate = function() {
        return undefined;
      };
      expression.isUserControlled = function() {
        // we don't know, so to be sure we say yes
        return true;
      };
      break;
  }
}
<|endoftext|>