<commit_before>import { decodeBase64Url } from './utils'

class LoginService {
  constructor (
    $http,
    $window,
    config,
    sessionService,
    toastService,
    mainService,
    userSessionService
  ) {
    this.$http = $http
    this.$window = $window
    this.config = config
    this.sessionService = sessionService
    this.toastService = toastService
    this.mainService = mainService
    this.userSessionService = userSessionService
  }

  createUser (username, token) {
    const data = {
      username,
      token
    }
    const opts = {
      headers: {
        'x-api-key': this.config.middleware.key
      }
    }
    return this.$http.post(this.config.middleware.url + '/users', data, opts)
  }

  handleLoginError (error) {
    let message = 'Could not log you in'
    if (error && error.data && error.data.message) {
      message += `. The response was "${error.data.message}".`
    }
    return this.toastService.error('login-failed', message)
  }

  init (session) {
    this.mainService.init(session)
    return session
  }

  navLogin () {
    this.$window.location.href = this.config.nav + '/SignIn.aspx'
  }

  navLogout () {
    this.$window.location.href = this.config.nav + '/SignOut.aspx'
  }

  loginOrCreateUser (username, token) {
    const retry = () => {
      return this.createUser(username, token)
        .then(() => this.sessionService.login(username, token))
    }
    return this.sessionService.login(username, token)
      .catch(retry)
  }

  canActivate () {
    const isValidSession = (local, remote) => {
      if (!remote.ok) {
        return Promise.reject('session invalid')
      }
      if (!(remote.userCtx && remote.userCtx.name)) {
        return Promise.reject('missing user context in remote session')
      }
      if (!local.userName) {
        return Promise.reject('missing user name in local session')
      }
      if (remote.userCtx.name.toLowerCase() !== local.userName.toLowerCase()) {
        return Promise.reject(`session mismatch for user ${local.userName}`)
      }
    }

    const checkSession = localSession => {
      return this.sessionService.getSession()
        .then(remoteSession => isValidSession(localSession, remoteSession))
        .then(() => this.init(localSession))
        .catch(err => {
          if (!this.$window.navigator.onLine) {
            // User looks to be offline, grant login
            return this.init(localSession)
          }
          throw err
        })
    }

    return this.userSessionService.getSession()
      .then(localSession => checkSession(localSession))
      .catch(err => this.navLogin(err))
  }

  login (instruction) {
    if (!(instruction.params.username && instruction.params.token)) {
      return this.canActivate()
    }

    const username = this.$window.decodeURI(instruction.params.username)
      .toLowerCase()
    const token = decodeBase64Url(instruction.params.token)

    const diff = {
      lastLogin: new Date().toISOString()
    }

    return this.loginOrCreateUser(username, token)
      .then(() => this.sessionService.getUser(username))
      .then(session => this.userSessionService
        .updateRemoteSession(username, session, diff))
      .then(session => this.userSessionService.setSession(session))
      .then(session => this.init(session))
      .catch(err => this.handleLoginError(err))
  }

  logout () {
    return this.userSessionService.getSession()
      .then(session => this.sessionService.remove(session))
  }
}

LoginService.$inject = [
  '$http',
  '$window',
  '$rootRouter',
  'config',
  'sessionService',
  'toastService',
  'mainService',
  'userSessionService'
]

export default LoginService
<commit_msg>fix: forgot to remove loginservice from here<commit_after>import { decodeBase64Url } from './utils'

class LoginService {
  constructor (
    $http,
    $window,
    config,
    sessionService,
    toastService,
    mainService,
    userSessionService
  ) {
    this.$http = $http
    this.$window = $window
    this.config = config
    this.sessionService = sessionService
    this.toastService = toastService
    this.mainService = mainService
    this.userSessionService = userSessionService
  }

  createUser (username, token) {
    const data = {
      username,
      token
    }
    const opts = {
      headers: {
        'x-api-key': this.config.middleware.key
      }
    }
    return this.$http.post(this.config.middleware.url + '/users', data, opts)
  }

  handleLoginError (error) {
    let message = 'Could not log you in'
    if (error && error.data && error.data.message) {
      message += `. The response was "${error.data.message}".`
    }
    return this.toastService.error('login-failed', message)
  }

  init (session) {
    this.mainService.init(session)
    return session
  }

  navLogin () {
    this.$window.location.href = this.config.nav + '/SignIn.aspx'
  }

  navLogout () {
    this.$window.location.href = this.config.nav + '/SignOut.aspx'
  }

  loginOrCreateUser (username, token) {
    const retry = () => {
      return this.createUser(username, token)
        .then(() => this.sessionService.login(username, token))
    }
    return this.sessionService.login(username, token)
      .catch(retry)
  }

  canActivate () {
    const isValidSession = (local, remote) => {
      if (!remote.ok) {
        return Promise.reject('session invalid')
      }
      if (!(remote.userCtx && remote.userCtx.name)) {
        return Promise.reject('missing user context in remote session')
      }
      if (!local.userName) {
        return Promise.reject('missing user name in local session')
      }
      if (remote.userCtx.name.toLowerCase() !== local.userName.toLowerCase()) {
        return Promise.reject(`session mismatch for user ${local.userName}`)
      }
    }

    const checkSession = localSession => {
      return this.sessionService.getSession()
        .then(remoteSession => isValidSession(localSession, remoteSession))
        .then(() => this.init(localSession))
        .catch(err => {
          if (!this.$window.navigator.onLine) {
            // User looks to be offline, grant login
            return this.init(localSession)
          }
          throw err
        })
    }

    return this.userSessionService.getSession()
      .then(localSession => checkSession(localSession))
      .catch(err => this.navLogin(err))
  }

  login (instruction) {
    if (!(instruction.params.username && instruction.params.token)) {
      return this.canActivate()
    }

    const username = this.$window.decodeURI(instruction.params.username)
      .toLowerCase()
    const token = decodeBase64Url(instruction.params.token)

    const diff = {
      lastLogin: new Date().toISOString()
    }

    return this.loginOrCreateUser(username, token)
      .then(() => this.sessionService.getUser(username))
      .then(session => this.userSessionService
        .updateRemoteSession(username, session, diff))
      .then(session => this.userSessionService.setSession(session))
      .then(session => this.init(session))
      .catch(err => this.handleLoginError(err))
  }

  logout () {
    return this.userSessionService.getSession()
      .then(session => this.sessionService.remove(session))
  }
}

LoginService.$inject = [
  '$http',
  '$window',
  'config',
  'sessionService',
  'toastService',
  'mainService',
  'userSessionService'
]

export default LoginService
<|endoftext|>


<commit_before>import {
  React, Provider,
  PropTypes, observer, observable, styled, action,
} from 'vendor';
import Theme                from '../theme';
import Toasts               from 'shared/components/toasts';
import Course               from '../models/course';
import { Logo }             from './navbar/logo';
import { Menus }            from './navbar/menus';
import TermsModal           from './terms-modal';
import { Navbar }           from './navbar.js';
import CourseNagModal       from './course-nag';
import ErrorMonitoring      from './error-monitoring';
import { NavbarContext }    from './navbar/context';
import { SecondaryToolbar } from './navbar/secondary-toolbar';

const StyledLayout = styled.div`
  min-height: 100vh;
`;

const Content = styled.div`
  padding-top: ${Theme.navbars.top.height};
  padding-bottom: ${Theme.navbars.bottom.height};
`;

class CourseContext {
  @observable course;
  constructor(c) { this.course = c; }
}

@observer
class TutorLayout extends React.Component {

  static propTypes = {
    course: PropTypes.instanceOf(Course),
    children: PropTypes.node.isRequired,
  }

  @observable secondaryTopControls;

  courseContext = new CourseContext(this.props.course);
  topNavbarContext = new NavbarContext();
  bottomNavbarContext = new NavbarContext();

  constructor(props) {
    super(props);
    this.topNavbarContext.left.set('logo', () => <Logo />);
    this.topNavbarContext.right.set('menu', () => <Menus />);
  }

  @action.bound setSecondaryTopControls(controls) {
    this.secondaryTopControls = controls;
  }

  componentDidUpdate() {
    this.courseContext.course = this.props.course;
  }

  render() {
    const { course } = this.props;

    return (
      <Provider
        topNavbar={this.topNavbarContext}
        courseContext={this.courseContext}
        bottomNavbar={this.bottomNavbarContext}
        setSecondaryTopControls={this.setSecondaryTopControls}
      >
        <StyledLayout>
          <Navbar
            area="header"
            context={this.topNavbarContext}
            isDocked={Boolean(this.secondaryTopControls)}
          />
          {this.secondaryTopControls &&
            <SecondaryToolbar
              controls={this.secondaryTopControls}
            />}
          <ErrorMonitoring />
          <TermsModal />
          <Toasts />
          <CourseNagModal
            key={course || 'no-course'}
            course={course}
          />
          <Content>{this.props.children}</Content>
          <Navbar
            area="footer"
            context={this.bottomNavbarContext}
          />
        </StyledLayout>
      </Provider>
    );
  }

}

export { TutorLayout };
<commit_msg>only add bottom padding for navbar if it exists<commit_after>import {
  React, Provider,
  PropTypes, observer, observable, styled, action,
} from 'vendor';
import Theme                from '../theme';
import Toasts               from 'shared/components/toasts';
import Course               from '../models/course';
import { Logo }             from './navbar/logo';
import { Menus }            from './navbar/menus';
import TermsModal           from './terms-modal';
import { Navbar }           from './navbar.js';
import CourseNagModal       from './course-nag';
import ErrorMonitoring      from './error-monitoring';
import { NavbarContext }    from './navbar/context';
import { SecondaryToolbar } from './navbar/secondary-toolbar';

const StyledLayout = styled.div`
  min-height: 100vh;
`;

const Content = styled.div`
  padding-top: ${Theme.navbars.top.height};
  padding-bottom: ${props => props.hasFooter ? Theme.navbars.bottom.height : 0};
`;

class CourseContext {
  @observable course;
  constructor(c) { this.course = c; }
}

@observer
class TutorLayout extends React.Component {

  static propTypes = {
    course: PropTypes.instanceOf(Course),
    children: PropTypes.node.isRequired,
  }

  @observable secondaryTopControls;

  courseContext = new CourseContext(this.props.course);
  topNavbarContext = new NavbarContext();
  bottomNavbarContext = new NavbarContext();

  constructor(props) {
    super(props);
    this.topNavbarContext.left.set('logo', () => <Logo />);
    this.topNavbarContext.right.set('menu', () => <Menus />);
  }

  @action.bound setSecondaryTopControls(controls) {
    this.secondaryTopControls = controls;
  }

  componentDidUpdate() {
    this.courseContext.course = this.props.course;
  }

  render() {
    const { course } = this.props;

    return (
      <Provider
        topNavbar={this.topNavbarContext}
        courseContext={this.courseContext}
        bottomNavbar={this.bottomNavbarContext}
        setSecondaryTopControls={this.setSecondaryTopControls}
      >
        <StyledLayout>
          <Navbar
            area="header"
            context={this.topNavbarContext}
            isDocked={Boolean(this.secondaryTopControls)}
          />
          {this.secondaryTopControls &&
            <SecondaryToolbar
              controls={this.secondaryTopControls}
            />}
          <ErrorMonitoring />
          <TermsModal />
          <Toasts />
          <CourseNagModal
            key={course || 'no-course'}
            course={course}
          />
          <Content hasFooter={!this.bottomNavbarContext.isEmpty}>
            {this.props.children}
          </Content>
          <Navbar
            area="footer"
            context={this.bottomNavbarContext}
          />
        </StyledLayout>
      </Provider>
    );
  }

}

export { TutorLayout };
<|endoftext|>


<commit_before>//==================================================
//  Task
//  test:css
//  For the description see
//  [SupeflyCSS Test Task](https://github.com/superflycss/task-test/)
//  IMPLEMENTATION
//  0: Support nunjucks template rendering within test markup
//  1: Cheerio copies content from `Test-markup`
//     and appends it to the markup to the `Test-render`
//
//==================================================

var gulp = require('gulp');
// -0-
var nunjucksRender = require('gulp-nunjucks-render');

// -1-
var highlight = require('gulp-highlight');
var dom  = require('gulp-jsdom');
var gutil = require('gulp-util');

var transform = require('vinyl-transform');
var predentation = require('predentation');

var pre = transform(function(options) {
  return predentation(options);
});

var PLI = require('@superflycss/pli');

var renderTestBlock = '\n

';

function insertAfter(referenceNode, newNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

//---------------------------------
gulp.task('test:css', function() {
  return gulp
    .src(PLI.SRC_TEST_HTML)
    .pipe(nunjucksRender({
      path: [PLI.src.main.nunjucks]
    }))
    .pipe(dom(function(document){
        document.querySelectorAll('.Test_markup > code').forEach((node)=>
        {
          var markup = node.innerHTML;
          var testDescriptionNode =
          node.parentElement.parentElement.nextElementSibling.querySelector('.Test_description');
          var renderTestBlock = document.createElement('div');
          renderTestBlock.innerHTML = markup;
          renderTestBlock.setAttribute('class', "Test_render");
          insertAfter(testDescriptionNode, renderTestBlock);
        });
    }))
    .pipe(highlight())
    .pipe(pre)
    .pipe(gulp.dest(PLI.target.test.html));
});
<commit_msg>Moved the nunjucks rendering step after the copy and append markup step<commit_after>//==================================================
//  Task
//  test:css
//  For the description see
//  [SupeflyCSS Test Task](https://github.com/superflycss/task-test/)
//  IMPLEMENTATION
//  0: Support nunjucks template rendering within test markup
//  1: Cheerio copies content from `Test-markup`
//     and appends it to the markup to the `Test-render`
//
//==================================================

var gulp = require('gulp');
// -0-
var nunjucksRender = require('gulp-nunjucks-render');

// -1-
var highlight = require('gulp-highlight');
var dom  = require('gulp-jsdom');
var gutil = require('gulp-util');

var transform = require('vinyl-transform');
var predentation = require('predentation');

var pre = transform(function(options) {
  return predentation(options);
});

var PLI = require('@superflycss/pli');

var renderTestBlock = '\n

';

function insertAfter(referenceNode, newNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

//---------------------------------
gulp.task('test:css', function() {
  return gulp
    .src(PLI.SRC_TEST_HTML)
    .pipe(dom(function(document){
        document.querySelectorAll('.Test_markup > code').forEach((node)=>
        {
          var markup = node.innerHTML;
          var testDescriptionNode =
          node.parentElement.parentElement.nextElementSibling.querySelector('.Test_description');
          var renderTestBlock = document.createElement('div');
          renderTestBlock.innerHTML = markup;
          renderTestBlock.setAttribute('class', "Test_render");
          insertAfter(testDescriptionNode, renderTestBlock);
        });
    }))
    .pipe(nunjucksRender({
      path: [PLI.src.main.nunjucks]
    }))
    .pipe(highlight())
    .pipe(pre)
    .pipe(gulp.dest(PLI.target.test.html));
});
<|endoftext|>


<commit_before>'use strict';

var sequencer = require('./sequencer'),
  playbackSlot = require('./playbackSlot'),
  playersPool = require('./playersPool'),
  playerFactory = require('./playerFactory'),
  defaults = require('lodash-node/modern/objects/defaults'),
  noop = require('lodash-node/modern/utilities/noop');

/**
 * @typedef {Object} Video
 * @property {string} provider
 * @property {string} id
 */

/**
 * @typedef {SequencerState} PlaybackState
 */

/**
 * @typedef {Object} playbackConfig
 * @property {function: Element} elementProducer
 * @property {function(*): Video} videoProducer
 * @property {function(*): *} nextEntryProducer
 * @property {number} transitionDuration
 * @property {?function(Video, ?Video)} comingNext
 * @property {?function(PlaybackState, PlaybackState)} stateChanged
 */

/**
 * Creates the "Playback" facade.
 *
 * @param {playbackConfig} config
 * @returns {Playback}
 */
function playback(config) {

  /** @type {playbackConfig} */
  var _config = defaults({}, config, {comingNext: noop, stateChanged: noop}),

    _playersPool = playersPool({
      playerFactory: playerFactory({
        elementProducer: _config.elementProducer
      })
    });

  /**
   * @param {{entry: Entry, endingSoon: function, ending: function}} slotProducerCfg
   * @returns {PlaybackSlot}
   */
  function playbackSlotProducer(slotProducerCfg) {
    return playbackSlot({
      entry: slotProducerCfg.entry,
      videoProducer: _config.videoProducer,
      transitionDuration: _config.transitionDuration,
      cues: {
        endingSoon: {
          time: function(duration) {
            return duration - _config.transitionDuration * 2;
          },
          callback: slotProducerCfg.endingSoon
        },
        ending: {
          time: function(duration) {
            return duration - _config.transitionDuration;
          },
          callback: slotProducerCfg.ending
        }
      },
      playersPool: _playersPool
    });
  }

  var _sequencer = sequencer({
    nextEntryProducer: _config.nextEntryProducer,
    playbackSlotProducer: playbackSlotProducer,
    comingNext: _config.comingNext
  });

  /**
   * @typedef Playback
   * @name Playback
   */
  var Playback = {
    play: _sequencer.play,
    pause: _sequencer.pause,
    skip: _sequencer.skip
  };

  return Object.freeze(Playback);
}

playback.States = sequencer.States;

module.exports = playback;
<commit_msg>- fixed playback doc<commit_after>'use strict';

var sequencer = require('./sequencer'),
  playbackSlot = require('./playbackSlot'),
  playersPool = require('./playersPool'),
  playerFactory = require('./playerFactory'),
  defaults = require('lodash-node/modern/objects/defaults'),
  noop = require('lodash-node/modern/utilities/noop');

/**
 * @typedef {Object} Video
 * @property {string} provider
 * @property {string} id
 */

/**
 * @typedef {SequencerState} PlaybackState
 */

/**
 * @typedef {Object} playbackConfig
 * @property {function: Element} elementProducer
 * @property {function(*): Video} videoProducer
 * @property {function(*): *} nextEntryProducer
 * @property {number} transitionDuration
 * @property {?function(Video, ?Video)} comingNext
 * @property {?function(PlaybackState, PlaybackState)} stateChanged
 * @property {?function(Entry, ?Error)} loadFailed
 */

/**
 * Creates the "Playback" facade.
 *
 * Transition is triggered at "transitionDuration" before the end of the media and the "comingNext: is notified
 * 2 times "transitionDuration" before the end.
 *
 * @param {playbackConfig} config
 * @returns {Playback}
 */
function playback(config) {

  /** @type {playbackConfig} */
  var _config = defaults({}, config, {comingNext: noop, stateChanged: noop}),

    _playersPool = playersPool({
      playerFactory: playerFactory({
        elementProducer: _config.elementProducer
      })
    });

  /**
   * @param {{entry: Entry, endingSoon: function, ending: function}} slotProducerCfg
   * @returns {PlaybackSlot}
   */
  function playbackSlotProducer(slotProducerCfg) {
    return playbackSlot({
      entry: slotProducerCfg.entry,
      videoProducer: _config.videoProducer,
      transitionDuration: _config.transitionDuration,
      cues: {
        endingSoon: {
          time: function(duration) {
            return duration - _config.transitionDuration * 2;
          },
          callback: slotProducerCfg.endingSoon
        },
        ending: {
          time: function(duration) {
            return duration - _config.transitionDuration;
          },
          callback: slotProducerCfg.ending
        }
      },
      playersPool: _playersPool
    });
  }

  var _sequencer = sequencer({
    nextEntryProducer: _config.nextEntryProducer,
    playbackSlotProducer: playbackSlotProducer,
    comingNext: _config.comingNext
  });

  /**
   * @typedef Playback
   * @name Playback
   */
  var Playback = {
    play: _sequencer.play,
    pause: _sequencer.pause,
    skip: _sequencer.skip
  };

  return Object.freeze(Playback);
}

playback.States = sequencer.States;

module.exports = playback;
<|endoftext|>


<commit_before>'use strict'

module.exports = {

  types: [
    {value: 'feat', name: 'feat:     A new feature'},
    {value: 'fix', name: 'fix:      A bug fix'},
    {value: 'docs', name: 'docs:     Documentation only changes'},
    {value: 'style', name: 'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)'},
    {value: 'refactor', name: 'refactor: A code change that neither fixes a bug nor adds a feature'},
    {value: 'perf', name: 'perf:     A code change that improves performance'},
    {value: 'test', name: 'test:     Adding missing tests'},
    {value: 'chore', name: 'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation'},
    {value: 'revert', name: 'revert:   Revert to a commit'},
    {value: 'ts', name: 'ts:   Typescript/Typings related changes'}
  ],

  scopes: [
    {name: 'Controller'},
    {name: 'Computed'},
    {name: 'DependencyStore'},
    {name: 'Model'},
    {name: 'Module'},
    {name: 'Views'},
    {name: 'Operators'},
    {name: 'Devtools'},
    {name: 'Providers'},
    {name: 'router'},
    {name: 'function-tree'},
    {name: 'demos'},
    {name: 'todomvc'},
    {name: 'forms'},
    {name: 'http'},
    {name: 'useragent'},
    {name: 'shortcuts'},
    {name: 'firebase'},
    {name: 'firebase-admin'},
    {name: 'storage'},
    {name: 'website'},
    {name: 'tutorial'},
    {name: 'react'},
    {name: 'inferno'},
    {name: 'preact'},
    {name: 'vue'},
    {name: 'angular'},
    {name: 'mobx'},
    {name: 'fluent'}
  ],

  // it needs to match the value for field type. Eg.: 'fix'
  scopeOverrides: {
    chore: []
  },

  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix'],
  appendBranchNameToCommitMessage: false
}
<commit_msg>chore: add proxy as scope<commit_after>'use strict'

module.exports = {

  types: [
    {value: 'feat', name: 'feat:     A new feature'},
    {value: 'fix', name: 'fix:      A bug fix'},
    {value: 'docs', name: 'docs:     Documentation only changes'},
    {value: 'style', name: 'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)'},
    {value: 'refactor', name: 'refactor: A code change that neither fixes a bug nor adds a feature'},
    {value: 'perf', name: 'perf:     A code change that improves performance'},
    {value: 'test', name: 'test:     Adding missing tests'},
    {value: 'chore', name: 'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation'},
    {value: 'revert', name: 'revert:   Revert to a commit'},
    {value: 'ts', name: 'ts:   Typescript/Typings related changes'}
  ],

  scopes: [
    {name: 'Controller'},
    {name: 'Computed'},
    {name: 'DependencyStore'},
    {name: 'Model'},
    {name: 'Module'},
    {name: 'Views'},
    {name: 'Operators'},
    {name: 'Devtools'},
    {name: 'Providers'},
    {name: 'router'},
    {name: 'function-tree'},
    {name: 'demos'},
    {name: 'todomvc'},
    {name: 'forms'},
    {name: 'http'},
    {name: 'useragent'},
    {name: 'shortcuts'},
    {name: 'firebase'},
    {name: 'firebase-admin'},
    {name: 'storage'},
    {name: 'website'},
    {name: 'tutorial'},
    {name: 'react'},
    {name: 'inferno'},
    {name: 'preact'},
    {name: 'vue'},
    {name: 'angular'},
    {name: 'mobx'},
    {name: 'fluent'},
    {name: 'proxy'}
  ],

  // it needs to match the value for field type. Eg.: 'fix'
  scopeOverrides: {
    chore: []
  },

  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix'],
  appendBranchNameToCommitMessage: false
}
<|endoftext|>


<commit_before>/*
 * ProduceModule
 * https://github.com/mkatanski/grunt-produce
 *
 * Copyright (c) 2015 Michał Katański
 * Licensed under the MIT license.
 */

var ProduceModule = (function () {

    require('shelljs/global');

    function ProduceModule(grunt) {
        this.grunt = grunt;

        this.path = require('path');
        this.inquirer = require('inquirer');
        this._ = require('lodash');

        this.NEW_LINE = '\n';
        if(/^win/.test(process.platform)) {
            this.NEW_LINE = '\r\n';
        }

        this.options = {};
        this.variables = {};
        this.destinationFile = '';
        this.template = [];
    }

    /**
     * Replace variables in string
     *
     * @param str {string} String to search for variables
     * @returns {string} Expanded string
     */
    ProduceModule.prototype.expandString = function (str) {
        for (var varName in this.variables) {
            if (!this.variables.hasOwnProperty(varName)) {
                continue;
            }
            // TODO: Add warning about non existing variables with optional line number
            str = str.replace('{{' + varName + '}}', this.variables[varName]);
        }
        return str;
    };

    /**
     * Replace variables in template file
     */
    ProduceModule.prototype.expandTemplate = function () {
        var _this = this;
        // for each line in template
        this.template.forEach(function (line, lineIndex) {
            // expand template line
            _this.template[lineIndex] = _this.expandString(line);
        });
    };

    /**
     * Get array of questions for user
     */
    ProduceModule.prototype.getQuestions = function () {
        var _questions = [],
            i = 0;
        // for each available variable
        for (var varName in this.variables) {
            if (!this.variables.hasOwnProperty(varName)) {
                continue;
            }
            // create new question object
            _questions[i] = {
                name   : varName,
                message: varName,
                default: this.variables[varName]
            };
            i++;
        }
        return _questions;
    };

    /**
     * Create variables to use in template
     * @returns {boolean} Return false if no variables were passed in via CLI
     */
    ProduceModule.prototype._prepareVariables = function () {
        // number of collected variables via CLI
        var _variablesCount = 0;

        // Assign to variables object initial values
        this.options.variables['username'] = this.options.username;
        this.options.variables['email'] = this.options.email;

        if (this.grunt.util.kindOf(this.options.variables) === 'object') {
            // for each defined variable collect variable value
            for (var varName in this.options.variables) {
                if (!this.options.variables.hasOwnProperty(varName)) {
                    continue;
                }
                // if variable is passed in via CLI
                if (this.grunt.option(varName)) {
                    // increment counter
                    _variablesCount++;
                }
                // assign variable value
                this.variables[varName] = this.grunt.option(varName) || this.options.variables[varName];
            }
        }
        return  (_variablesCount !== 0);
    };

    /**
     * Check if options are correct
     */
    ProduceModule.prototype._checkOptions = function () {
        if (this.grunt.util.kindOf(this.options.fileName) !== 'function' &&
            this.grunt.util.kindOf(this.options.fileName) !== 'string') {
            throw 'fileName is required and must be a string or function';
        }

        if (this.grunt.util.kindOf(this.options.template) !== 'string') {
            throw 'template is required and must be a string';
        }

        // Check if template file exists
        // TODO: Template can be also a regular string, not file path
        if (!this.grunt.file.exists(this.options.template)) {
            throw 'Template doesn\'t exists! [' + this.options.template + ']';
        }

        if (this.options.fileOverwrite !== 'block' && this.options.fileOverwrite !== 'warning') {
            throw 'options.fileOverwrite must be equal to "block" or "warning"!';
        }
    };

    /**
     * Save destination file as expanded template
     */
    ProduceModule.prototype.saveFile = function () {
        // if fileName is a function, run it passing variables as an argument
        if (this.grunt.util.kindOf(this.options.fileName) === 'function') {
            this.options.fileName = this.options.fileName(this.variables);
        }

        // Replace variables in file name
        this.options.fileName = this.expandString(this.options.fileName);
        // Create destination path
        this.destinationFile = this.path.join(this.options.fileName);

        // Replace variables in template file
        this.expandTemplate();

        // Check if destination file exists
        if (this.grunt.file.exists(this.destinationFile)) {
            if (this.options.fileOverwrite === 'block') {
                throw 'Destination file exists! [' + this.destinationFile + ']';
            }
            if (this.options.fileOverwrite === 'warning') {
                this.grunt.log.errorlns('Destination file will be overwriten! [' + this.destinationFile + ']');
            }
        }

        // Save file
        this.grunt.file.write(this.destinationFile, this.template.join(this.NEW_LINE));
        this.grunt.log.writeln('File saved as: ' + this.destinationFile);
    };

    /**
     * Get git config
     *
     * @param configName {string} git config name
     * @returns {string} Git config value
     * @private
     */
    ProduceModule.prototype._getGitConfig = function (configName) {
        return exec('git config ' + configName, {silent:true}).output.replace('\n', '');
    };

    /**
     * Asynchronously prompt user for variables values
     *
     * @param async {object} grunt async object
     * @param callback {function} callback function which is triggered after prompting is complete
     */
    ProduceModule.prototype.promptUserAsync = function(async, callback) {
        var _this = this;

        _this.inquirer.prompt(_this.getQuestions(), function (answers) {
            _this._(answers).forEach(function (answer, varName) {
                // assign user answers to variable
                _this.variables[varName] = answer;
            });
            // finish async mode
            async();
            // run callback function
            callback();
        });
    };

    /**
     * Setup module, collect all required data and load template file
     *
     * @param options {object} Grunt options
     */
    ProduceModule.prototype.setup = function (options) {
        // assign options to class object
        this.options = options;

        // Get GIT config values for username and user e-mail
        // (empty string as default if loading data from git config was unsuccessful)
        this.options.username = this._getGitConfig('user.name') || '';
        this.options.email = this._getGitConfig('user.email') || '';

        // Prepare defined variables and check if prompting for variable values is required
        this.promptUser = !this._prepareVariables();

        this._checkOptions();

        // Read template file
        this.template = this.grunt.file.read(this.options.template).split(this.NEW_LINE);

    };

    return ProduceModule;
})();

module.exports = ProduceModule;
<commit_msg>feat(app): Add warning about non existing variables<commit_after>/*
 * ProduceModule
 * https://github.com/mkatanski/grunt-produce
 *
 * Copyright (c) 2015 Michał Katański
 * Licensed under the MIT license.
 */

var ProduceModule = (function () {

    require('shelljs/global');

    function ProduceModule(grunt) {
        this.grunt = grunt;

        this.path = require('path');
        this.inquirer = require('inquirer');
        this._ = require('lodash');

        this.NEW_LINE = '\n';
        if(/^win/.test(process.platform)) {
            this.NEW_LINE = '\r\n';
        }

        this.options = {};
        this.variables = {};
        this.destinationFile = '';
        this.template = [];
    }

    /**
     * Replace variables in string
     *
     * @param str {string} String to search for variables
     * @returns {string} Expanded string
     */
    ProduceModule.prototype.expandString = function (str) {
        for (var varName in this.variables) {
            if (!this.variables.hasOwnProperty(varName)) {
                continue;
            }
            str = str.replace('{{' + varName + '}}', this.variables[varName]);
        }
        return str;
    };

    /**
     * Replace variables in template file
     */
    ProduceModule.prototype.expandTemplate = function () {
        var _this = this;
        // for each line in template
        this.template.forEach(function (line, lineIndex) {
            // expand template line
            var _expandedLine = _this.expandString(line),
                _unusedMatches = _expandedLine.match(/{{(.*?)}}/g);

            if (_unusedMatches !== null) {
                // display warning about all unused variables
                _unusedMatches.forEach(function(unusedVar){
                    _this.grunt.log.errorlns(
                        'Found unused variable in template: ' + unusedVar + ' on line ' + (lineIndex + 1)
                    );
                });
            }

            _this.template[lineIndex] = _expandedLine;
        });
    };

    /**
     * Get array of questions for user
     */
    ProduceModule.prototype.getQuestions = function () {
        var _questions = [],
            i = 0;
        // for each available variable
        for (var varName in this.variables) {
            if (!this.variables.hasOwnProperty(varName)) {
                continue;
            }
            // create new question object
            _questions[i] = {
                name   : varName,
                message: varName,
                default: this.variables[varName]
            };
            i++;
        }
        return _questions;
    };

    /**
     * Create variables to use in template
     * @returns {boolean} Return false if no variables were passed in via CLI
     */
    ProduceModule.prototype._prepareVariables = function () {
        // number of collected variables via CLI
        var _variablesCount = 0;

        // Assign to variables object initial values
        this.options.variables['username'] = this.options.username;
        this.options.variables['email'] = this.options.email;

        if (this.grunt.util.kindOf(this.options.variables) === 'object') {
            // for each defined variable collect variable value
            for (var varName in this.options.variables) {
                if (!this.options.variables.hasOwnProperty(varName)) {
                    continue;
                }
                // if variable is passed in via CLI
                if (this.grunt.option(varName)) {
                    // increment counter
                    _variablesCount++;
                }
                // assign variable value
                this.variables[varName] = this.grunt.option(varName) || this.options.variables[varName];
            }
        }
        return  (_variablesCount !== 0);
    };

    /**
     * Check if options are correct
     */
    ProduceModule.prototype._checkOptions = function () {
        if (this.grunt.util.kindOf(this.options.fileName) !== 'function' &&
            this.grunt.util.kindOf(this.options.fileName) !== 'string') {
            throw 'fileName is required and must be a string or function';
        }

        if (this.grunt.util.kindOf(this.options.template) !== 'string') {
            throw 'template is required and must be a string';
        }

        // Check if template file exists
        // TODO: Template can be also a regular string, not file path
        if (!this.grunt.file.exists(this.options.template)) {
            throw 'Template doesn\'t exists! [' + this.options.template + ']';
        }

        if (this.options.fileOverwrite !== 'block' && this.options.fileOverwrite !== 'warning') {
            throw 'options.fileOverwrite must be equal to "block" or "warning"!';
        }
    };

    /**
     * Save destination file as expanded template
     */
    ProduceModule.prototype.saveFile = function () {
        // if fileName is a function, run it passing variables as an argument
        if (this.grunt.util.kindOf(this.options.fileName) === 'function') {
            this.options.fileName = this.options.fileName(this.variables);
        }

        // Replace variables in file name
        this.options.fileName = this.expandString(this.options.fileName);
        // Create destination path
        this.destinationFile = this.path.join(this.options.fileName);

        // Replace variables in template file
        this.expandTemplate();

        // Check if destination file exists
        if (this.grunt.file.exists(this.destinationFile)) {
            if (this.options.fileOverwrite === 'block') {
                throw 'Destination file exists! [' + this.destinationFile + ']';
            }
            if (this.options.fileOverwrite === 'warning') {
                this.grunt.log.errorlns('Destination file will be overwriten! [' + this.destinationFile + ']');
            }
        }

        // Save file
        this.grunt.file.write(this.destinationFile, this.template.join(this.NEW_LINE));
        this.grunt.log.writeln('File saved as: ' + this.destinationFile);
    };

    /**
     * Get git config
     *
     * @param configName {string} git config name
     * @returns {string} Git config value
     * @private
     */
    ProduceModule.prototype._getGitConfig = function (configName) {
        return exec('git config ' + configName, {silent:true}).output.replace('\n', '');
    };

    /**
     * Asynchronously prompt user for variables values
     *
     * @param async {object} grunt async object
     * @param callback {function} callback function which is triggered after prompting is complete
     */
    ProduceModule.prototype.promptUserAsync = function(async, callback) {
        var _this = this;

        _this.inquirer.prompt(_this.getQuestions(), function (answers) {
            _this._(answers).forEach(function (answer, varName) {
                // assign user answers to variable
                _this.variables[varName] = answer;
            });
            // finish async mode
            async();
            // run callback function
            callback();
        });
    };

    /**
     * Setup module, collect all required data and load template file
     *
     * @param options {object} Grunt options
     */
    ProduceModule.prototype.setup = function (options) {
        // assign options to class object
        this.options = options;

        // Get GIT config values for username and user e-mail
        // (empty string as default if loading data from git config was unsuccessful)
        this.options.username = this._getGitConfig('user.name') || '';
        this.options.email = this._getGitConfig('user.email') || '';

        // Prepare defined variables and check if prompting for variable values is required
        this.promptUser = !this._prepareVariables();

        this._checkOptions();

        // Read template file
        this.template = this.grunt.file.read(this.options.template).split(this.NEW_LINE);

    };

    return ProduceModule;
})();

module.exports = ProduceModule;
<|endoftext|>


<commit_before>import React from 'react';
<commit_msg>Modified Comments component<commit_after>import React from 'react';

const Comments =  React.createClass({
  renderComment(comment, i){
    return(

          {comment.user}
          {comment.text}
          <button className="remove-comment">×</button>

    )

  },
  render(){
    return(

        {this.props.postComments.map(this.renderComment)}
        <form ref="commentForm" className="comment-form">
          <input type="text" ref="author" placeholder="author"/>
          <input type="text" ref="comment" placeholder="comment"/>
          <input type="submit" hidden/>
        </form>

    )
  }
});

export default Comments;
<|endoftext|>


<commit_before>'use strict';

var util = require( 'util' );

const WHITESPACE = " \n\t\v\r";
const BARE_INTERRUPT = "\"'()|";
const QUOTES = "\"'";
const NEGATORS = "n-!";
const PARENS = "()";
const ORS = "|o";

class term {
    constructor ( id ) {
        if (
            ! typeof id === 'string' &&
            ! id instanceof String
        ) {
            throw `invalid term: '${id}'`;
        } else if ( id.length === 0 ) {
            throw 'invalid, empty term';
        }
        this.id = id;
    }
};

class expr {
    constructor ( subexprs ) {
        this._children = [];
        if ( subexprs instanceof Array )
            this._children = subexprs;
        this.negated = false;
    }
    negate () {
        this.negated = !this.negated;
    }
};

class conj extends expr {
    constructor ( subexprs ) {
        super( subexprs );
    }
};

// TODO: remove
function dbg ( msg ) {
    console.log( `DBG: ${msg}` );
}

class parser {
    constructor ( raw_query ) {
        dbg( 'parser init' );
        this.i = 0;
        this.raw = raw_query;
        this.q = this.ps_query();
    }

    static parse ( raw_query ) {
        try {
            return (new parser( raw_query )).q;
        } catch ( e ) {
            return null;
        }
    }

    _c () { return this.raw[ this.i ]; }
    _end () { return this.i === this.raw.length; }
    _step ( n ) {
        n = n || 1;
        this.i += n;
    }

    ps_query () {
        dbg( 'ps_query()' );
        let buf = [];
        while ( !this._end() && this._c() !== ')' ) {
            this.ps_ws();
            buf.push( this.ps_expr() );
            this.ps_ws();
        }
        return new expr( buf );
    }

    ps_expr () {
        dbg( `ps_expr(), char '${this._c()}'` );
        // expr -> _ ( quoted | neg | paren | or | term ) _
        if ( QUOTES.indexOf( this._c() ) !== -1 ) {
            return this.ps_quoted();
        } else if ( NEGATORS.indexOf( this._c().toLowerCase() ) !== -1 ) {w
            return this.ps_neg();
        } else if ( this._c() === '(' ) {
            return this.ps_paren();
        } else {
            return this.ps_bare();
        }
    }

    ps_ws () {
        dbg( 'ps_ws():' );
        var begin = this.i;
        while ( WHITESPACE.indexOf( this._c() ) !== -1 )
            this._step();
        return this.i !== begin;
    }

    ps_quoted () {
        dbg( `ps_quoted(), '${this.raw[ this.i + 1 ]}'` );
        let open = this.i;
        this._step();
        while ( !this._end() && this._c() !== this.raw[ open ] )
            this._step();
        if ( this._c() === this.raw[ open ] ) {
            this.i++;
            return new expr([
                new term( this.raw.slice( open + 1, this.i - 1 ) )
            ]);
        }
        throw `unterminated quote (${this.raw[ open ]})`;
    }

    ps_neg () {
        dbg( 'ps_neg():' );
        if ( this._c() === '!' || this._c() === '-' )
            this._step();
        else if ( this.raw.slice( i, i + 3 ).toLowerCase() === 'not' )
            this._step( 3 );
        this.ps_ws();
        let e = ps_expr();
        if ( e instanceof expr )
            return e.negate();
        else
            throw 'dangling not';
    }

    ps_paren () {
        dbg( 'ps_paren():' );
        this._step();
        this.ps_ws();
        let e = this.ps_query();
        this.ps_ws();
        if ( this._c() !== ')' )
            throw 'unterminted paranthetical';
        this._step();
        return e;
    }

    ps_bare () {
        dbg( `ps_bare(), char '${this._c()}'` );
        let start = this.i;
        while (
            !this._end() &&
            BARE_INTERRUPT.indexOf( this._c() ) === -1 &&
            WHITESPACE.indexOf( this._c() ) === -1
        ) this._step();
        return new expr([
            new term( this.raw.slice( start, this.i ) )
        ]);
    }

    ps_or () {

    }

};
<commit_msg>getCanonical()<commit_after>'use strict';
var util = require( 'util' );

const I_WHITESPACE = " \n\t\v\r"; // ASCII whitespace
const I_NEGATION = "!-n";         // negators '!', '-' and 'not'
const I_BAREINT = "\"'()|";       // characters that will interrupt bare terms
const I_TERMPAREN = ')';
const I_QUOTES = "\"'";

const T_CONJ = 0;
const T_DISJ = 1;
const T_OR = 2;
const T_TERM = 3;

class expr {
    constructor ( subexprs ) {
        this._children = [];
        if ( subexprs instanceof Array )
            this._children = subexprs;
        this.negated = false;
    }
    negate () {
        this.negated = !this.negated;
        return this;
    }
    getType () {
        return T_CONJ;
    }
    getSize () {
        let totalSize = 0;
        this._children.forEach( ( child ) => {
            if ( child instanceof expr ) {
                totalSize += child.getSize();
            } else if ( child instanceof term ) {
                totalSize++;
            }
        } );
        return totalSize;
    }

    // TODO: distributivism of conj and disj, remove parens

    getCanonical () {
        let canonical = '';
        if ( this.negated )
            canonical += 'NOT ';
        canonical += '( ';
        this._children.forEach( ( child ) => {
            canonical += child.getCanonical();
            if ( child !== this._children[ this._children.length - 1 ] )
                canonical += ' ';
        } );
        canonical += ' )';
        return canonical;
    }
};

class term extends expr {
    constructor ( id ) {
        super([]);
        if (
            ! typeof id === 'string' &&
            ! id instanceof String
        ) {
            throw `invalid term: '${id}'`;
        } else if ( id.length === 0 ) {
            throw 'invalid, empty term';
        }
        this.id = id;
    }
    getType() {
        return T_TERM;
    }
    getCanonical () {
        var escaped = this.id.replace( /"/, "\"" );
        return ( this.negated ? '-' : '' ) + '"' + escaped + '"';
    }
};

class disj extends expr {
    constructor ( subexprs ) {
        super( subexprs );
    }
    getType () {
        return T_DISJ;
    }
    getCanonical () {
        let canonical = '';
        if ( this.negated )
            canonical += 'NOT ';
        canonical += '( ';
        this._children.forEach( ( child ) => {
            canonical += child.getCanonical();
            if ( child !== this._children[ this._children.length - 1 ] )
                canonical += ' OR ';
        } );
        canonical += ' )';
        return canonical;
    }
};

class or extends expr {
    constructor () {
        super();
    }
    getType () {
        return T_OR;
    }
}

class parser {
    constructor ( raw ) {
        this.raw = raw;
        this.i = 0;
        this.debug = false;
    }

    _c () {
        return this.raw[ this.i ];
    }

    _end () {
        return this.i >= this.raw.length;
    }

    _step ( n ) {
        this.i += ( n || 1 );
    }

    _dbg ( msg ) {
        if ( !this.debug ) return;
        console.log( `DEBUG: ${msg}` );
    }

    _dump () {
        var marker = '';
        for ( var i = 0; i < this.i + 1; i++ )
            marker += ' ';
        marker += '^';
        this._dbg( ` [${this.raw}] (idx=${this.i}/${this.raw.length})` );
        this._dbg( ` ${marker}` );
    }

    parse () {
        return this.ps_query();
    }

    ps_query () {
        let buf = [];
        while ( !this._end() && this._c() != I_TERMPAREN ) {
            let b = this.ps_expr();
            if ( b instanceof expr && b.getType() !== T_OR ) {
                buf.push( b );
                this.ps_ws();
                continue;
            }
            if ( buf.length === 0 )
                throw 'dangling or (start of query)';
            if ( buf[ buf.length - 1 ].getType() === T_OR )
                throw 'two consecutive or\'s';
            let pos_b = this.i;
            let c = this.ps_expr();
            if ( c === null )
                throw 'dangling or (end of query)';
            if ( c.getType() === T_OR )
                throw 'two consecutive or\'s';
            buf.push( new disj([ buf.pop(), c ]) );
            this.ps_ws();
        }
        return new expr( buf );
    }

    ps_expr () {
        // expr -> _ ( quoted | neg | paren | disj | term ) _
        this.ps_ws();
        this._dump();
        if ( this._end() ) {
            this._dbg( 'end of stream' );
            return null;
        }
        if ( this.peek_or() !== false ) {
            this.ps_or();
            return new or();
        } else if ( I_QUOTES.indexOf( this._c() ) !== -1 ) {
            return this.ps_quoted();
        } else if ( I_NEGATION.indexOf( this._c().toLowerCase() ) !== -1 ) {
            return this.ps_neg();
        } else if ( this._c() === '(' ) {
            return this.ps_paren();
        } else {
            return this.ps_bare();
        }
        ps_ws();
    }

    ps_ws () {
        let begin = this.i;
        while ( I_WHITESPACE.indexOf( this._c() ) !== -1 )
            this._step();
        return begin === this.i;
    }

    ps_quoted () {
        this._dbg( 'quoted term' );
        let open = this.i;
        this._step();
        while ( !this._end() && this._c() !== this.raw[ open ] )
            this._step();
        if ( this._c() !== this.raw[ open ] )
        throw `unterminated quote (${this.raw[ open ]})`;
        this._step();
        return new expr([
            new term( this.raw.slice( open + 1, this.i - 1 ) )
        ]);
    }

    ps_neg () {
        this._dbg( 'negated term' );
        if ( this._c() === '!' || this._c() === '-' )
            this._step();
        else if ( this.raw.slice( this.i, this.i + 3 ).toLowerCase() === 'not' )
            this._step( 3 );
        try {
            return new expr([ this.ps_expr().negate() ]);
        } catch ( e ) {
            throw typeof e === 'string'
                ? 'dangling not' :
                `dangling not (${e})`;
        }

    }

    ps_paren () {
        this._dbg( 'paranthetical' );
        this._step();
        this.ps_ws();
        let e = this.ps_query();
        this.ps_ws();
        if ( this._c() !== I_TERMPAREN )
            throw 'unterminted paranthetical';
        this._dbg( 'paranthetical, end' );
        this._step();
        return e instanceof expr ? e : null;
    }

    ps_bare () {
        this._dbg( 'bare term' );
        let start = this.i;
        while (
            !this._end() &&
            I_BAREINT.indexOf( this._c() ) === -1 &&
            I_WHITESPACE.indexOf( this._c() ) === -1
        ) {
            this._dbg( `bare char (${this.raw[ this.i ]})` );
            this._step();
        }
        this._dump();
        return new expr([
            new term( this.raw.slice( start, this.i ) )
        ]);
    }

    peek_or () {
        let begin = this.i;
        let ans = this.ps_or( true );
        this.i = begin;
        return ans;
    }

    ps_or ( suppress_dbg ) {
        if ( !suppress_dbg )
            this._dbg( 'OR marker' );
        if ( this.raw.substr( this.i, 2 ).toLowerCase() === 'or' ) {
            this._step( 2 );
            return true;
        } else if ( this.raw[ this.i ] === '|' ) {
            this._step();
            return true;
        } else {
            return false;
        }
    }
};

// TODO: get rid of
var x = [
    'hello world',
    'another test',
    'austin "danger" powers',
    'George Herman"Babe"Ruth',
    "  Ivan('the terrible')IV  ",
    'John ( not McDermott ) ( !"Big Bad John" -England)',
    "Allan or 'White Lightening' or Donald"
];
x.forEach( ( item ) => {
    let ps = (new parser( item ));
    //ps.debug = true;
    var q = ps.parse();
    console.log(
        util.inspect( { q: q, canonical: q.getCanonical() }, { depth: 10, colors: true } )
    );
} );

<|endoftext|>


<commit_before>'use strict';

angular.module('phoenixeye')
.service('PollSvc', [
	'$q',
	'$http',
	'$timeout',
	'$rootScope',
	function PollSvc($q, $http, $timeout, $rootScope) {
		var defaultTimeout = 3000;

		//list of promises for polls
		var pollers = [];

		//stop all pollers on state change
		$rootScope.$on('$stateChangeSuccess', function () {
			pollers.forEach(function (poller) {
				poller.stopped = true;
			});
		});

		return {
			pollUntil: function(httpConfig, stopCondition, timeout) {
				timeout = timeout || defaultTimeout;

				var deferred = $q.defer();
				pollers.push(deferred);

				//error from server
				function errorHandler(resp, status) {
					deferred.reject(resp);
				}

				function successHandler(resp, status) {
					//not stopped
					if( deferred.stopped ) {
						return deferred.reject();
					}

					//stop condition not met, try again
					if( ! stopCondition(resp) ) {
						$timeout(function () {
							$http(httpConfig)
								.success(successHandler)
								.error(errorHandler)
							;
						}, timeout);
					} else {
						deferred.resolve(resp);
					}
				}

				$http(httpConfig)
					.success(successHandler)
					.error(errorHandler)
				;

				return deferred;
			}
		}
	}
]);<commit_msg>dont stop poller if dest state is image<commit_after>'use strict';

angular.module('phoenixeye')
.service('PollSvc', [
	'$q',
	'$http',
	'$timeout',
	'$rootScope',
	function PollSvc($q, $http, $timeout, $rootScope) {
		var defaultTimeout = 3000;

		//list of promises for polls
		var pollers = [];

		//stop all pollers on state change
		$rootScope.$on('$stateChangeSuccess', function (event, toState) {
			if( toState.name === 'image' ) return;

			pollers.forEach(function (poller) {
				poller.stopped = true;
			});
		});

		return {
			pollUntil: function(httpConfig, stopCondition, timeout) {
				timeout = timeout || defaultTimeout;

				var deferred = $q.defer();
				pollers.push(deferred);

				//error from server
				function errorHandler(resp, status) {
					deferred.reject(resp);
				}

				function successHandler(resp, status) {
					//not stopped
					if( deferred.stopped ) {
						return deferred.reject();
					}

					//stop condition not met, try again
					if( ! stopCondition(resp) ) {
						$timeout(function () {
							$http(httpConfig)
								.success(successHandler)
								.error(errorHandler)
							;
						}, timeout);
					} else {
						deferred.resolve(resp);
					}
				}

				$http(httpConfig)
					.success(successHandler)
					.error(errorHandler)
				;

				return deferred;
			}
		}
	}
]);<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const _            = require('lodash');
const split2       = require('split2');

const RemoteError = require('./RemoteError');

/**
 * Structure that describes a running shipment action
 * and emits events for every incoming object event
 */
class RunningAction extends EventEmitter {

    /**
     * @param {ShipmentClient} client
     * @param {String} action
     * @param {Object} args
     * @param {Readable} stream
     */
    constructor(client, action, args, stream) {
        super();
        this.client = client;
        this.action = action;
        this.args   = args;
        this.stream = stream;
        this.stream
            .pipe(split2())
            .on('data', line => {
                this.receiveLine(line);
            })
            .on('end', () => {
                this.emit('end');
            });
    }

    /**
     * Parse incoming line
     *
     * @param {String} line
     */
    receiveLine(line) {
        if (_.startsWith(line, 'SHIPMENT')) {
            this.receiveShipmentLogLine(line);
        }
        let obj;
        try {
            obj = JSON.parse(line);
            if (!obj.context)
            // object doesn't contain "context" property, probably not a shipment JSON line
            // so emit as normal "log" line anyways
                return this.emit('log', line);
        } catch (e) {
            // Couldn't parse the line as JSON, emit as "log"
            return this.emit('log', line);
        }
        return this.emit('emit', obj);
    }

    /**
     * Parse a shipment (internal) log line, verifying the key to check the origin of the info
     *
     * @param {String} line
     */
    receiveShipmentLogLine(line) {

        let matches;

        let prefix = `SHIPMENT-${this.client.verifyKey}: `;

        let match = (verb, line) => new RegExp(`${prefix}${verb}: (.*)`).exec(line);

        if (line === `${prefix}ok`)
            this.emit('success');

        else if ((matches = match('start', line)))
            this.emit('start', matches[1]);

        else if ((matches = match('error', line)))
            this.emit('error', new RemoteError(matches[1]));
    }
}

module.exports = RunningAction;<commit_msg>documentation / formatting<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const _            = require('lodash');
const split2       = require('split2');

const RemoteError = require('./RemoteError');

/**
 * Structure that represents a running shipment action
 * and emits events for every incoming line
 */
class RunningAction extends EventEmitter {

    /**
     * @param {ShipmentClient} client
     * @param {String} action
     * @param {Object} args
     * @param {Readable} stream
     */
    constructor(client, action, args, stream) {
        super();
        this.client = client;
        this.action = action;
        this.args   = args;
        this.stream = stream;
        this.stream
            .pipe(split2())
            .on('data', line => {
                this.receiveLine(line);
            })
            .on('end', () => {
                this.emit('end');
            });
    }

    /**
     * Parse incoming line
     *
     * @param {String} line
     */
    receiveLine(line) {
        if (_.startsWith(line, 'SHIPMENT')) {
            this.parseLifecycleEvent(line);
        }
        let obj;
        try {
            obj = JSON.parse(line);
            if (!obj.context)
            // object doesn't contain "context" property, probably not a shipment JSON line
            // so emit as normal "log" line anyways
                return this.emit('log', line);
        } catch (e) {
            // Couldn't parse the line as JSON, emit as "log"
            return this.emit('log', line);
        }
        return this.emit('emit', obj);
    }

    /**
     * Parse a shipment (internal) "lifecycle event", verifying the key to check the integrity of the info
     * And emit appropriate event
     * e.g. SHIPMENT-12345: ok
     *
     * @param {String} line
     */
    parseLifecycleEvent(line) {

        let matches;

        let prefix = `SHIPMENT-${this.client.verifyKey}: `;

        let match = (verb, line) => new RegExp(`${prefix}${verb}: (.*)`).exec(line);

        if (line === `${prefix}ok`)
            return this.emit('success');

        if ((matches = match('start', line)))
            return this.emit('start', matches[1]);

        if ((matches = match('error', line)))
            return this.emit('error', new RemoteError(matches[1]));
    }
}

module.exports = RunningAction;<|endoftext|>


<commit_before>/**
* Twitter Test Class Hashtag
* @version 201703242300
*/

// Load Modules
console.log("\033[2m");
var express = require("express");
console.log("- Carregando Modulos");
var twitter = require('twitter');
var credential = require("./credential");

// Express Object
console.log("- Carregando Express");
var app = express();

// Twitter Object
console.log("- Carregando Twitter (API)");
var client = new twitter({
  consumer_key: credential.consumer_key,
  consumer_secret: credential.consumer_secret,
  access_token_key: credential.access_token_key,
  access_token_secret: credential.access_token_secret
});

// Start Monitor
console.log("\033[0m");
console.log("\033[1m");
console.log(" Monitor de Mensagens Ativado! Por favor enviem um tweet com a hashtag #ast06.");
console.log("\033[0m");
var stream = client.stream('statuses/filter', {track: '#love'});
stream.on('data', function(tweet) {
    var text = "";
    // Author
    text += "\033[0m";
    text += "\n--\n";
    text += "\033[1m";
    text += "\033[34m";
    text += " " + tweet.user.name + " (@" + tweet.user.screen_name + ")\n";
    // Tweet
    text += "\033[0m";
    text += "\033[39m";
    text += "\033[3m";
    text += " " + tweet.text + "\n";
    text += "\033[0m";
    text += "--\n"
    console.log(text);
    setTimeout(function(){ /* Wait */}, 2000);
});

// Error Stream
stream.on('error', function() {});
<commit_msg>Start Version<commit_after>/**
* Twitter Test Class Hashtag
* @version 201703242300
*/

// Load Modules
console.log("\033[2m");
var express = require("express");
console.log("- Carregando Modulos");
var twitter = require('twitter');
var credential = require("./credential");

// Express Object
console.log("- Carregando Express");
var app = express();

// Twitter Object
console.log("- Carregando Twitter (API)");
var client = new twitter({
  consumer_key: credential.consumer_key,
  consumer_secret: credential.consumer_secret,
  access_token_key: credential.access_token_key,
  access_token_secret: credential.access_token_secret
});

// Start Monitor
console.log("\033[0m");
console.log("\033[1m");
console.log(" Monitor de Mensagens Ativado! Por favor enviem um tweet com a hashtag #ast06.");
console.log("\033[0m");
var stream = client.stream('statuses/filter', {track: '#ast06'});
stream.on('data', function(tweet) {
    var text = "";
    // Author
    text += "\033[0m";
    text += "\n--\n";
    text += "\033[1m";
    text += "\033[34m";
    text += " " + tweet.user.name + " (@" + tweet.user.screen_name + ")\n";
    // Tweet
    text += "\033[0m";
    text += "\033[39m";
    text += "\033[3m";
    text += " " + tweet.text + "\n";
    text += "\033[0m";
    text += "--\n"
    console.log(text);
    setTimeout(function(){ /* Wait */}, 2000);
});

// Error Stream
stream.on('error', function() {});
<|endoftext|>


<commit_before>var Graphics = (function()
{
  var _pixi = {};

  _pixi.createStage = function(bgColor) {
    _pixi.stage = new PIXI.Stage(bgColor);
  }

  _pixi.createRenderer = function(width, height, useCanvas) {
    if (useCanvas) {
      _pixi.renderer = new PIXI.CanvasRenderer(width, height);
    } else {
      _pixi.renderer = new PIXI.autoDetectRenderer(width, height, null, false, false);
    }

    document.body.appendChild(_pixi.renderer.view);
  }

  _pixi.draw = function() {
    _pixi.renderer.render(_pixi.stage);
  }

  _pixi.initialize = function(options) {
    options = js.defaults(options, {
      bgColor: 0x66ff99,
      useCanvas: false,
      width: 640,
      height: 480
    });

    _pixi.createStage(options.bgColor);
    _pixi.createRenderer(options.width, options.height, options.useCanvas);
  }

  var _commonSpriteDefaults = function(options) {
    return js.defaults(options, {
      wireframe: false,
      color: 0xff0000
    });
  }

  var _createDebugSprite = function(options, drawCallback) {
    options = js.defaults(_commonSpriteDefaults(options));

    var context = new PIXI.Graphics();

    var outlineWeight = 1.0;
    var outlineAlpha = 1.0;
    context.lineStyle(outlineWeight, options.color, outlineAlpha);

    var fillAlpha = options.wireframe ? 1.0 : 0.3;
    context.beginFill(options.color, fillAlpha);

    drawCallback(context);

    context.endFill();

    return context;
  }

  _pixi.drawBoxSprite = function(width, height, options) {
    return _createDebugSprite(options, function(context) {
      var halfWidth = width / 2.0;
      var halfHeight = height / 2.0;
      context.drawRect(-halfWidth, -halfHeight, width, height);
      context.moveTo(0, 0);
      context.lineTo(halfWidth, 0);
    });
  }

  _pixi.drawCircleSprite = function(radius, options) {
    return _createDebugSprite(options, function(context) {
      context.drawCircle(0, 0, radius);
      context.moveTo(0,0);
      context.lineTo(0, radius);
    });
  }

  _pixi.removeSprite = function(sprite) {
    this.stage.removeChild(sprite);
  }

  var api = {}

  var _drawDebugSprites = false;
  var _debugSprites = [];

  var _transientDebugSprites = [];

  var _destroyAllTransientSprites = function() {
    _transientDebugSprites.forEach(function(sprite) {
      _pixi.removeSprite(sprite);
    });
  }

  api.initialize = function(options) {
    _pixi.initialize(options);
  };

  api.addDisplayObject = function(displayObject)
  {
    _pixi.stage.addChild(displayObject);
  };

  api.draw = function(dt) {
    _pixi.draw();
    _destroyAllTransientSprites();
  };

  api.enableDebugSprites = function() {
    if (!_drawDebugSprites) {
      _debugSprites.forEach(function(sprite) {
        api.addDisplayObject(sprite);
      });
    }
    _drawDebugSprites = true;
  }

  api.disableDebugSprites = function() {
    if (_drawDebugSprites) {
      _debugSprites.forEach(function(sprite) {
        _pixi.removeSprite(sprite);
      });
    }
    _drawDebugSprites = false;
  }

  var _addDebugSprite = function(options, spriteCallback) {
    options = js.defaults(options, {
      transient: true
    });
    var sprite = spriteCallback();
    api.addDisplayObject(sprite);
    if (options.transient) {
      _transientDebugSprites.push(sprite);
    } else {
      _debugSprites.push(sprite);
    }
    return sprite;
  }

  api.addDebugBox = function(width, height, options) {
    return _addDebugSprite(options, function() {
      return _pixi.drawBoxSprite(width, height, options)
    });
  }

  api.addDebugCircle = function(radius, options) {
    return _addDebugSprite(options, function() {
      return _pixi.drawCircleSprite(radius, options)
    });
  }

return api; }).call();
<commit_msg>Wireframe looks cool again.<commit_after>var Graphics = (function()
{
  var _pixi = {};

  _pixi.createStage = function(bgColor) {
    _pixi.stage = new PIXI.Stage(bgColor);
  }

  _pixi.createRenderer = function(width, height, useCanvas) {
    if (useCanvas) {
      _pixi.renderer = new PIXI.CanvasRenderer(width, height);
    } else {
      _pixi.renderer = new PIXI.autoDetectRenderer(width, height, null, false, false);
    }

    document.body.appendChild(_pixi.renderer.view);
  }

  _pixi.draw = function() {
    _pixi.renderer.render(_pixi.stage);
  }

  _pixi.initialize = function(options) {
    options = js.defaults(options, {
      bgColor: 0x66ff99,
      useCanvas: false,
      width: 640,
      height: 480
    });

    _pixi.createStage(options.bgColor);
    _pixi.createRenderer(options.width, options.height, options.useCanvas);
  }

  var _commonSpriteDefaults = function(options) {
    return js.defaults(options, {
      wireframe: false,
      color: 0xff0000
    });
  }

  var _createDebugSprite = function(options, drawCallback) {
    options = js.defaults(_commonSpriteDefaults(options));

    var context = new PIXI.Graphics();

    var outlineWeight = 1.0;
    var outlineAlpha = 1.0;
    context.lineStyle(outlineWeight, options.color, outlineAlpha);

    var fillAlpha = options.wireframe ? 0.3 : 1.0;
    context.beginFill(options.color, fillAlpha);

    drawCallback(context);

    context.endFill();

    return context;
  }

  _pixi.drawBoxSprite = function(width, height, options) {
    return _createDebugSprite(options, function(context) {
      var halfWidth = width / 2.0;
      var halfHeight = height / 2.0;
      context.drawRect(-halfWidth, -halfHeight, width, height);
      context.moveTo(0, 0);
      context.lineTo(halfWidth, 0);
    });
  }

  _pixi.drawCircleSprite = function(radius, options) {
    return _createDebugSprite(options, function(context) {
      context.drawCircle(0, 0, radius);
      context.moveTo(0,0);
      context.lineTo(0, radius);
    });
  }

  _pixi.removeSprite = function(sprite) {
    this.stage.removeChild(sprite);
  }

  var api = {}

  var _drawDebugSprites = false;
  var _debugSprites = [];

  var _transientDebugSprites = [];

  var _destroyAllTransientSprites = function() {
    _transientDebugSprites.forEach(function(sprite) {
      _pixi.removeSprite(sprite);
    });
  }

  api.initialize = function(options) {
    _pixi.initialize(options);
  };

  api.addDisplayObject = function(displayObject)
  {
    _pixi.stage.addChild(displayObject);
  };

  api.draw = function(dt) {
    _pixi.draw();
    _destroyAllTransientSprites();
  };

  api.enableDebugSprites = function() {
    if (!_drawDebugSprites) {
      _debugSprites.forEach(function(sprite) {
        api.addDisplayObject(sprite);
      });
    }
    _drawDebugSprites = true;
  }

  api.disableDebugSprites = function() {
    if (_drawDebugSprites) {
      _debugSprites.forEach(function(sprite) {
        _pixi.removeSprite(sprite);
      });
    }
    _drawDebugSprites = false;
  }

  var _addDebugSprite = function(options, spriteCallback) {
    options = js.defaults(options, {
      transient: true
    });
    var sprite = spriteCallback();
    api.addDisplayObject(sprite);
    if (options.transient) {
      _transientDebugSprites.push(sprite);
    } else {
      _debugSprites.push(sprite);
    }
    return sprite;
  }

  api.addDebugBox = function(width, height, options) {
    return _addDebugSprite(options, function() {
      return _pixi.drawBoxSprite(width, height, options)
    });
  }

  api.addDebugCircle = function(radius, options) {
    return _addDebugSprite(options, function() {
      return _pixi.drawCircleSprite(radius, options)
    });
  }

return api; }).call();
<|endoftext|>


<commit_before>(function () {
  const $ = window.Bliss
  const Mavo = window.Mavo
  const firebase = window.firebase

  Mavo.Backend.register($.Class({
    extends: Mavo.Backend,
    id: 'Firebase',
    constructor: function (databaseUrl) {
      let id = this.mavo.id || 'mavo'
      let config = {}

      let initUsingAttributes = /^https:\/\/.*\.firebaseio\.com$/.test(databaseUrl)

      // Init Firebase using attributes
      if (initUsingAttributes) {
        config = {
          apiKey: this.mavo.element.getAttribute('mv-firebase-api-key'),
          authDomain: this.mavo.element.getAttribute('mv-firebase-auth-domain'),
          databaseURL: databaseUrl,
          storageBucket: this.mavo.element.getAttribute('mv-firebase-storage-bucket')
        }

        if (!config.apiKey) {
          return this.mavo.error('Firebase: mv-firebase-api-key attribute missing')
        }

        // Support using multiple apps on the same page
        if (!firebase.apps.length) {
          this.app = firebase.initializeApp(config)
        } else {
          this.app = firebase.initializeApp(config, `app${firebase.apps.length}`)
        }
      } else {
        // Init firebase using script
        config = firebase.default.app().options

        if (!config.apiKey) {
          return this.mavo.error('Firebase: apiKey missing from config')
        }

        this.app = firebase.default
      }

      this.statusChangesCallbacks = []
      this.changesCallbacks = []

      // PERMISSIONS
      let unauthenticatedPermissionsAttr = this.mavo.element.getAttribute('mv-unauthenticated-permissions')
      let authenticatedPermissionsAttr = this.mavo.element.getAttribute('mv-authenticated-permissions')

      let authenticatedPermissions = getPermissions(authenticatedPermissionsAttr) || ['read', 'edit', 'add', 'delete', 'save', 'logout']

      // Use default permissions if unauthenticated-permissions isn't specified,
      // attribute 'firebase-auth-domain' has to be set if permission 'login' is used
      let unauthenticatedPermissions = getPermissions(unauthenticatedPermissionsAttr)
      if (unauthenticatedPermissions) {
        if (!config.authDomain && unauthenticatedPermissions.includes('login')) {
          if (initUsingAttributes) {
            return this.mavo.error('Firebase: authDomain missing from config (needed if permission \'login\' is specified)')
          } else {
            return this.mavo.error('Firebase: firebase-auth-domain attribute missing (needed if permission \'login\' is specified)')
          }
        }
      } else {
        if (config.authDomain) {
          unauthenticatedPermissions = ['read', 'login']
        } else {
          unauthenticatedPermissions = ['read']
        }
      }

      this.defaultPermissions = {
        authenticated: authenticatedPermissions,
        unauthenticated: unauthenticatedPermissions
      }

      this.permissions.on(this.defaultPermissions.unauthenticated)

      this.db = this.app.database().ref(id)

      // STORAGE

      // Only allow file uploading if storageBucket is defined
      if (config.storageBucket) {
        this.storage = this.app.storage().ref(id)

        this.upload = function (file) {
          let ref = this.storage.child(`${file.name}-${Date.now()}`)

          return ref.put(file).then(() => {
            return ref.getDownloadURL()
          })
        }
      }

      // Firebase auth changes
      this.app.auth().onAuthStateChanged(user => {
        if (!user) {
          return
        }

        this.permissions.off(this.defaultPermissions.unauthenticated).on(this.defaultPermissions.authenticated)
        this.user = {
          username: user.email,
          name: user.displayName,
          avatar: user.photoURL
        }
      }, error => {
        this.mavo.error('Firebase: ' + error.message)
      })

      // HELPER FUNCTIONS

      function getPermissions (attr) {
        if (attr) {
          return attr.split(/\s+/)
        } else if (attr === '') {
          return []
        }
      }
    },

    onStatusChange: function (callback) {
      this.statusChangesCallbacks.push(callback)

      if (this.listeningOnStatus) {
        return
      }
      this.listeningOnStatus = true

      this.app.database().ref('.info/connected').on('value', snap => {
        this.statusChangesCallbacks.forEach(callback => callback(snap.val()))
      })
    },

    onChange: function (callback) {
      this.changesCallbacks.push(callback)

      if (this.listeningOnValue) {
        return
      }
      this.listeningOnValue = true

      this.db.on('value', snapshot => {
        let doc = snapshot.val()

        if (!doc || !doc._rev || doc._rev <= this.rev) {
          return
        }

        this.rev = doc._rev

        this.changesCallbacks.forEach(callback => callback(doc))
      })
    },

    load: function () {
      return this.db.once('value').then(snapshot => {
        let data = snapshot.val()

        if (!data) {
          this.rev = 1
          return {}
        }

        this.rev = data._rev || 1
        return data
      })
    },

    store: function (data) {
      // TODO: How about conflicts?

      return this.db.transaction(currentData => {
        this.rev = (this.rev || 0) + 1

        if (currentData && currentData._rev) {
          this.rev = currentData._rev + 1
        }

        return Object.assign(data, {
          _rev: this.rev
        })
      })
    },

    login: function () {
      return this.ready.then(() => {
        if (this.user) {
          return
        }

        let provider = new this.app.auth.GoogleAuthProvider()

        return this.app.auth().signInWithPopup(provider).catch(error => {
          this.mavo.error('Firebase: ' + error.message)
          return Promise.reject(error)
        })
      })
    },

    logout: function () {
      return this.app.auth().signOut().then(() => {
        // Sign-out successful.
        this.permissions.off(this.defaultPermissions.authenticated).on(this.defaultPermissions.unauthenticated)
      }).catch((error) => {
        this.mavo.error('Firebase: ' + error.message)
      })
    },

    compareDocRevs: function (docA, docB) {
      // If b is newer return 1

      if (!docA || !docA._rev) {
        return 1
      }

      if (!docB || !docB._rev) {
        return -1
      }

      if (docA._rev === docB._rev) {
        return 0
      }

      return docA._rev < docB._rev ? 1 : -1
    },

    static: {
      test: url => /^(firebase|https:\/\/.*\.firebaseio\.com)$/.test(url)
    }
  }))
})()
<commit_msg>force rev to be an integer<commit_after>(function () {
  const $ = window.Bliss
  const Mavo = window.Mavo
  const firebase = window.firebase

  Mavo.Backend.register($.Class({
    extends: Mavo.Backend,
    id: 'Firebase',
    constructor: function (databaseUrl) {
      let id = this.mavo.id || 'mavo'
      let config = {}

      let initUsingAttributes = /^https:\/\/.*\.firebaseio\.com$/.test(databaseUrl)

      // Init Firebase using attributes
      if (initUsingAttributes) {
        config = {
          apiKey: this.mavo.element.getAttribute('mv-firebase-api-key'),
          authDomain: this.mavo.element.getAttribute('mv-firebase-auth-domain'),
          databaseURL: databaseUrl,
          storageBucket: this.mavo.element.getAttribute('mv-firebase-storage-bucket')
        }

        if (!config.apiKey) {
          return this.mavo.error('Firebase: mv-firebase-api-key attribute missing')
        }

        // Support using multiple apps on the same page
        if (!firebase.apps.length) {
          this.app = firebase.initializeApp(config)
        } else {
          this.app = firebase.initializeApp(config, `app${firebase.apps.length}`)
        }
      } else {
        // Init firebase using script
        config = firebase.default.app().options

        if (!config.apiKey) {
          return this.mavo.error('Firebase: apiKey missing from config')
        }

        this.app = firebase.default
      }

      this.statusChangesCallbacks = []
      this.changesCallbacks = []

      // PERMISSIONS
      let unauthenticatedPermissionsAttr = this.mavo.element.getAttribute('mv-unauthenticated-permissions')
      let authenticatedPermissionsAttr = this.mavo.element.getAttribute('mv-authenticated-permissions')

      let authenticatedPermissions = getPermissions(authenticatedPermissionsAttr) || ['read', 'edit', 'add', 'delete', 'save', 'logout']

      // Use default permissions if unauthenticated-permissions isn't specified,
      // attribute 'firebase-auth-domain' has to be set if permission 'login' is used
      let unauthenticatedPermissions = getPermissions(unauthenticatedPermissionsAttr)
      if (unauthenticatedPermissions) {
        if (!config.authDomain && unauthenticatedPermissions.includes('login')) {
          if (initUsingAttributes) {
            return this.mavo.error('Firebase: authDomain missing from config (needed if permission \'login\' is specified)')
          } else {
            return this.mavo.error('Firebase: firebase-auth-domain attribute missing (needed if permission \'login\' is specified)')
          }
        }
      } else {
        if (config.authDomain) {
          unauthenticatedPermissions = ['read', 'login']
        } else {
          unauthenticatedPermissions = ['read']
        }
      }

      this.defaultPermissions = {
        authenticated: authenticatedPermissions,
        unauthenticated: unauthenticatedPermissions
      }

      this.permissions.on(this.defaultPermissions.unauthenticated)

      this.db = this.app.database().ref(id)

      // STORAGE

      // Only allow file uploading if storageBucket is defined
      if (config.storageBucket) {
        this.storage = this.app.storage().ref(id)

        this.upload = function (file) {
          let ref = this.storage.child(`${file.name}-${Date.now()}`)

          return ref.put(file).then(() => {
            return ref.getDownloadURL()
          })
        }
      }

      // Firebase auth changes
      this.app.auth().onAuthStateChanged(user => {
        if (!user) {
          return
        }

        this.permissions.off(this.defaultPermissions.unauthenticated).on(this.defaultPermissions.authenticated)
        this.user = {
          username: user.email,
          name: user.displayName,
          avatar: user.photoURL
        }
      }, error => {
        this.mavo.error('Firebase: ' + error.message)
      })

      // HELPER FUNCTIONS

      function getPermissions (attr) {
        if (attr) {
          return attr.split(/\s+/)
        } else if (attr === '') {
          return []
        }
      }
    },

    onStatusChange: function (callback) {
      this.statusChangesCallbacks.push(callback)

      if (this.listeningOnStatus) {
        return
      }
      this.listeningOnStatus = true

      this.app.database().ref('.info/connected').on('value', snap => {
        this.statusChangesCallbacks.forEach(callback => callback(snap.val()))
      })
    },

    onChange: function (callback) {
      this.changesCallbacks.push(callback)

      if (this.listeningOnValue) {
        return
      }
      this.listeningOnValue = true

      this.db.on('value', snapshot => {
        let doc = snapshot.val()

        if (!doc || !doc._rev || doc._rev <= this.rev) {
          return
        }

        this.rev = doc._rev

        this.changesCallbacks.forEach(callback => callback(doc))
      })
    },

    load: function () {
      return this.db.once('value').then(snapshot => {
        let data = snapshot.val()

        if (!data) {
          this.rev = 1
          return {}
        }

        this.rev = data._rev || 1
        return data
      })
    },

    store: function (data) {
      // Always override server with current data, even if conflict

      return this.db.transaction(currentData => {
        if (currentData) {
          this.rev = Number.isInteger(currentData._rev) ? currentData._rev + 1 : 1
        } else {
          this.rev = 1
        }

        return Object.assign(data, {
          _rev: this.rev
        })
      })
    },

    login: function () {
      return this.ready.then(() => {
        if (this.user) {
          return
        }

        let provider = new this.app.auth.GoogleAuthProvider()

        return this.app.auth().signInWithPopup(provider).catch(error => {
          this.mavo.error('Firebase: ' + error.message)
          return Promise.reject(error)
        })
      })
    },

    logout: function () {
      return this.app.auth().signOut().then(() => {
        // Sign-out successful.
        this.permissions.off(this.defaultPermissions.authenticated).on(this.defaultPermissions.unauthenticated)
      }).catch((error) => {
        this.mavo.error('Firebase: ' + error.message)
      })
    },

    compareDocRevs: function (docA, docB) {
      // If b is newer return 1

      if (!docA || !Number.isInteger(docA._rev)) {
        return 1
      }

      if (!docB || !Number.isInteger(docB._rev)) {
        return -1
      }

      if (docA._rev === docB._rev) {
        return 0
      }

      return docA._rev < docB._rev ? 1 : -1
    },

    static: {
      test: url => /^(firebase|https:\/\/.*\.firebaseio\.com)$/.test(url)
    }
  }))
})()
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2014 microServiceBus.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* jshint node: true */
/* jshint esversion: 6 */
/* jshint strict:false */
'use strict';
var fs = require('fs');
var _ = require('underscore');
var moment = require('moment');
var util = require('util');
let path = require('path');

function TTLCollection(options) {
    const MAXCOLLECTIONCOUNT = 10000;
    var self = this;
    this.options = options;
    this._collection = [];
    var _fileName = path.resolve(options.persistDir, options.persistFileName);

    // Interval to check for expired items
    setInterval(function () {
        self._check();
    }, this.options.checkPeriod);

    // Interval (this.options.persistPeriod) for persising this._collection
    setInterval(function () {
        fs.writeFile(_fileName, JSON.stringify(self._collection), 'utf-8', function (err) {
            if (err)
                console.log('Unable to persist TTL Collection: ' + err);
        });

    }, this.options.persistPeriod);

    // Restore from last collection
    if (!fs.existsSync(options.persistDir)) {
        fs.mkdirSync(options.persistDir);
    }
    if (!fs.existsSync(_fileName)) {
        fs.writeFileSync(_fileName, "[]", 'utf-8');
    }
    fs.readFile(_fileName, (err, data) => {

        if (err) {
            console.log('Unable to desirialize TTL Collection: ' + err);
        }
        else {
            try {
                let collection = JSON.parse(data);
                if (collection)
                    this._collection = collection.concat(this._collection);
            }
            catch (e) { }
        }
    });

    // Evaluates each item in this.collection and removes old items
    TTLCollection.prototype._check = function () {
        if (this._collection.length > MAXCOLLECTIONCOUNT) {
            var delCount = this._collection.length - MAXCOLLECTIONCOUNT;

            console.log('History exeeded max length. Removing ' + delCount + ' items');

            this._collection.splice(0, delCount);
        }
        let firstNoneExpiredElement = this._collection.findIndex(function (element) {
            return !self._hasExpired(element);
        });
        if (firstNoneExpiredElement >= 0) {
            this._collection.splice(0, firstNoneExpiredElement);
        }
    };
    // Checks if item has expired
    TTLCollection.prototype._hasExpired = function (element) {
        return element.expire < Date.now();
    };
    // Adds item to this._collection
    TTLCollection.prototype.push = function (element, label, group) {
        this._collection.push({
            created: Date.now(),
            label: label,
            group: group,
            expire: Date.now() + self.options.ttl,
            val: element
        });
    };
    // Adds item to this._collection
    TTLCollection.prototype.pushUnique = function (element, label, group) {

        let item = this._collection.find(function (i) {
            return i.label === label && group === group;
        });

        if (item) {
            item.created = Date.now();
            item.group = group;
            item.expire = Date.now() + self.options.ttl;
            item.val = element;
        }
        else {
            this._collection.push({
                created: Date.now(),
                label: label,
                group: group,
                expire: Date.now() + self.options.ttl,
                val: element
            });
        }
    };
    TTLCollection.prototype.getLength = function () {
        return this._collection.length;
    };
    // Create an aggregated collection grouped by option.groupByUnit
    TTLCollection.prototype.groupCollection = function (unit, callback) {
        try {
            try {

                let groupedResults = _.groupBy(this._collection, (item) =>
                    moment(item.created).startOf(unit)
                );

                let result = _.map(groupedResults, function (arr, dt) {
                    return { dt: dt, count: arr.length };
                });

                callback(null, result);
            }
            catch (err) {
                callback(err);
            }

        }
        catch (err) {
            callback(err);
        }
    };
    // Returns a date (from, to) filtered aggregated collection
    TTLCollection.prototype.filterCollection = function (from, to, unit, callback) {
        try {
            try {
                let selction = this._collection.filter(function (element) {
                    return element.created >= from && element.created <= to;
                });

                let groupedResults = _.groupBy(selction, (item) =>
                    moment(item.created).startOf(unit)
                );

                let result = _.map(groupedResults, function (arr, dt) {
                    let label = arr.map(function (i) {
                        return i.label ? i.label + ':' : null;
                    }).join('');
                    return { dt: dt, count: arr.length, label: label };
                });

                callback(null, result);
            }
            catch (err) {
                callback(err);
            }

        }
        catch (err) {
            callback(err);
        }
    };
    // Returns a date (from, to) filtered aggregated collection
    TTLCollection.prototype.filterByGroup = function (group) {
        let groupCollection = this._collection.filter(function (i) {
            return i.group === group;
        });
        return groupCollection.map(function (i) {
            return i.val;
        });
    };
}

module.exports = TTLCollection;<commit_msg>Added persist prototype<commit_after>/*
The MIT License (MIT)

Copyright (c) 2014 microServiceBus.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* jshint node: true */
/* jshint esversion: 6 */
/* jshint strict:false */
'use strict';
var fs = require('fs');
var _ = require('underscore');
var moment = require('moment');
var util = require('util');
let path = require('path');

function TTLCollection(options) {
    const MAXCOLLECTIONCOUNT = 10000;
    var self = this;
    this.options = options;
    this._collection = [];
    var _fileName = path.resolve(options.persistDir, options.persistFileName);

    // Interval to check for expired items
    setInterval(function () {
        self._check();
    }, this.options.checkPeriod);

    // Interval (this.options.persistPeriod) for persising this._collection
    setInterval(function () {
        this.persist();
    }, this.options.persistPeriod);

    // Restore from last collection
    if (!fs.existsSync(options.persistDir)) {
        fs.mkdirSync(options.persistDir);
    }
    if (!fs.existsSync(_fileName)) {
        fs.writeFileSync(_fileName, "[]", 'utf-8');
    }
    fs.readFile(_fileName, (err, data) => {

        if (err) {
            console.log('Unable to desirialize TTL Collection: ' + err);
        }
        else {
            try {
                let collection = JSON.parse(data);
                if (collection)
                    this._collection = collection.concat(this._collection);
            }
            catch (e) { }
        }
    });
    TTLCollection.prototype.persist = function () {
        fs.writeFile(_fileName, JSON.stringify(self._collection), 'utf-8', function (err) {
            if (err)
                console.log('Unable to persist TTL Collection: ' + err);
        });
    };
    // Evaluates each item in this.collection and removes old items
    TTLCollection.prototype._check = function () {
        if (this._collection.length > MAXCOLLECTIONCOUNT) {
            var delCount = this._collection.length - MAXCOLLECTIONCOUNT;

            console.log('History exeeded max length. Removing ' + delCount + ' items');

            this._collection.splice(0, delCount);
        }
        let firstNoneExpiredElement = this._collection.findIndex(function (element) {
            return !self._hasExpired(element);
        });
        if (firstNoneExpiredElement >= 0) {
            this._collection.splice(0, firstNoneExpiredElement);
        }
    };
    // Checks if item has expired
    TTLCollection.prototype._hasExpired = function (element) {
        return element.expire < Date.now();
    };
    // Adds item to this._collection
    TTLCollection.prototype.push = function (element, label, group) {
        this._collection.push({
            created: Date.now(),
            label: label,
            group: group,
            expire: Date.now() + self.options.ttl,
            val: element
        });
    };
    // Adds item to this._collection
    TTLCollection.prototype.pushUnique = function (element, label, group) {

        let item = this._collection.find(function (i) {
            return i.label === label && group === group;
        });

        if (item) {
            item.created = Date.now();
            item.group = group;
            item.expire = Date.now() + self.options.ttl;
            item.val = element;
        }
        else {
            this._collection.push({
                created: Date.now(),
                label: label,
                group: group,
                expire: Date.now() + self.options.ttl,
                val: element
            });
        }
    };
    TTLCollection.prototype.getLength = function () {
        return this._collection.length;
    };
    // Create an aggregated collection grouped by option.groupByUnit
    TTLCollection.prototype.groupCollection = function (unit, callback) {
        try {
            try {

                let groupedResults = _.groupBy(this._collection, (item) =>
                    moment(item.created).startOf(unit)
                );

                let result = _.map(groupedResults, function (arr, dt) {
                    return { dt: dt, count: arr.length };
                });

                callback(null, result);
            }
            catch (err) {
                callback(err);
            }

        }
        catch (err) {
            callback(err);
        }
    };
    // Returns a date (from, to) filtered aggregated collection
    TTLCollection.prototype.filterCollection = function (from, to, unit, callback) {
        try {
            try {
                let selction = this._collection.filter(function (element) {
                    return element.created >= from && element.created <= to;
                });

                let groupedResults = _.groupBy(selction, (item) =>
                    moment(item.created).startOf(unit)
                );

                let result = _.map(groupedResults, function (arr, dt) {
                    let label = arr.map(function (i) {
                        return i.label ? i.label + ':' : null;
                    }).join('');
                    return { dt: dt, count: arr.length, label: label };
                });

                callback(null, result);
            }
            catch (err) {
                callback(err);
            }

        }
        catch (err) {
            callback(err);
        }
    };
    // Returns a date (from, to) filtered aggregated collection
    TTLCollection.prototype.filterByGroup = function (group) {
        let groupCollection = this._collection.filter(function (i) {
            return i.group === group;
        });
        return groupCollection.map(function (i) {
            return i.val;
        });
    };
}

module.exports = TTLCollection;<|endoftext|>