<commit_before>import React from 'react'
import { Row, Col, Input, Panel, SplitButton, MenuItem, Label, ButtonGroup, Button } from 'react-bootstrap'
import update from 'react-addons-update'

import allPermissions from './permissions'

export default class UserSettings extends React.Component {

  constructor (props) {
    super(props)
    this.state = {
      appAdminChecked: this.props.permissions.isApplicationAdmin(),
      currentProjectIndex: 0,
      projectSettings: {},
    }
    console.log(this.props.projects)
    this.props.projects.forEach((project, i) => {
      console.log(project.id)
      console.log(this.props.permissions)
      let access = 'none'
      let defaultFeeds = []
      let permissions = []
      console.log(this.props.permissions.hasProject(project.id))
      if(this.props.permissions.hasProject(project.id)) {
        if(this.props.permissions.isProjectAdmin(project.id)) {
          console.log('is admin')
          access = 'admin'
        }
        else {
          console.log('custom')
          access = 'custom'
          let projectPermissions = this.props.permissions.getProjectPermissions(project.id)
          permissions = projectPermissions.map((p) => { return p.type })
          defaultFeeds = this.props.permissions.getProjectDefaultFeeds(project.id)
        }
      }
      console.log({ access, defaultFeeds, permissions })
      this.state.projectSettings[project.id] = { access, defaultFeeds, permissions }
    })
    console.log(this.state)
  }

  getSettings () {
    console.log(this.state)
    if(this.state.appAdminChecked) {
      return {
        permissions: [{
          type: 'administer-application'
        }],
        projects: []
      }
    }

    let settings = { permissions: [], projects: [] }

    this.props.projects.forEach((project, i) => {
      let stateProjectSettings = this.state.projectSettings[project.id]
      if (stateProjectSettings.access === 'none') return

      let projectSettings = {
        project_id: project.id,
        permissions: []
      }
      if (stateProjectSettings.access === 'admin') {
        projectSettings.permissions.push({
          type: 'administer-project'
        })
      } else if (stateProjectSettings.access === 'custom') {
        projectSettings.defaultFeeds = stateProjectSettings.defaultFeeds
        // users have view-all permissions by default
        projectSettings.permissions.push({
          type: 'view-feed',
          feeds: ['*']
        })
        projectSettings.permissions = projectSettings.permissions.concat(stateProjectSettings.permissions.map((permission) => {
          return { type: permission }
        }))
      }
      settings.projects.push(projectSettings)
    })

    return settings
  }

  projectSelected (evt, key) {
    let currentProject = this.props.projects[key]
    this.setState({
      currentProjectIndex: key
    })
    console.log('project selected', key, currentProject)
  }

  appAdminClicked () {
    this.setState({
      appAdminChecked: this.refs['appAdminCheckbox'].getChecked()
    })
  }

  projectAccessUpdated(projectId, newAccess) {

    var stateUpdate = { projectSettings: { [projectId]: { $merge : { access : newAccess } } } };
    this.setState(update(this.state, stateUpdate));
    console.log('project access updated', stateUpdate)
    console.log(this.state)
  }

  projectFeedsUpdated(projectId, newFeeds) {
    var stateUpdate = { projectSettings: { [projectId]: { $merge : { defaultFeeds : newFeeds } } } };
    this.setState(update(this.state, stateUpdate));
  }

  projectPermissionsUpdated(projectId, newPermissions) {
    var stateUpdate = { projectSettings: { [projectId]: { $merge : { permissions : newPermissions } } } };
    this.setState(update(this.state, stateUpdate));
  }

  render () {
    let currentProject = this.props.projects[this.state.currentProjectIndex]

    let projectPanel = (
      <Panel header={

          Project Settings for
          <SplitButton
            title={currentProject.name}
            onSelect={this.projectSelected.bind(this)}
            pullRight
          >
            {this.props.projects.map((project, i) => {
              let settings = this.state.projectSettings[project.id]
              if (typeof settings !== 'undefined')
                return <MenuItem eventKey={i}>{project.name} {getProjectLabel(settings.access)}</MenuItem>
            })}
          </SplitButton>

      }
      >

      {this.props.projects.map((project, i) => {
        // console.log(projectSettings)
        let settings = this.state.projectSettings[project.id]
        return <ProjectSettings
          project={project}
          settings={settings}
          fetchProjectFeeds={this.props.fetchProjectFeeds}
          visible={(i === this.state.currentProjectIndex)}
          projectAccessUpdated={this.projectAccessUpdated.bind(this)}
          projectFeedsUpdated={this.projectFeedsUpdated.bind(this)}
          projectPermissionsUpdated={this.projectPermissionsUpdated.bind(this)}
        />
      })}
    </Panel>)

    return (
      <Row>
        <Col xs={4}>
          <Panel header={
Application Settings
}>
            <Input
              type='checkbox'
              label='Application Administrator'
              defaultChecked={this.state.appAdminChecked}
              onClick={this.appAdminClicked.bind(this)}
              ref='appAdminCheckbox'
            />
          </Panel>
        </Col>
        <Col xs={8}>
          {this.state.appAdminChecked
            ? Application administrators have full access to all projects.
            : projectPanel
          }
        </Col>
      </Row>
    )
  }
}

function getProjectLabel(access) {
  switch(access) {
    case 'none': return None
    case 'admin': return Admin
    case 'custom': return Custom
  }
}

class ProjectSettings extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      projectSettings: this.props.settings
    }
  }
  static propTypes = {
    project: React.PropTypes.object.isRequired,
    settings: React.PropTypes.object.isRequired
  }
  componentWillMount () {
    if (!this.props.project.feedSources) {
      console.log('fetchingFeeds for ' + this.props.project.id)
      this.props.fetchProjectFeeds(this.props.project.id)
    }
  }
  setAccess (access) {
    console.log(access)
    this.props.projectAccessUpdated(this.props.project.id, access)
  }

  feedsUpdated () {
    let selectedFeeds = []
    this.props.project.feedSources.forEach((feed) => {
      var checkbox = this.refs['feed-' + feed.id]
      if(checkbox.getChecked()) selectedFeeds.push(feed.id)
    })
    this.props.projectFeedsUpdated(this.props.project.id, selectedFeeds)
  }

  permissionsUpdated () {
    let selectedPermissions = []
    allPermissions.forEach((permission) => {
      var checkbox = this.refs['permission-' + permission.type]
      if(checkbox.getChecked()) selectedPermissions.push(permission.type)
    })
    this.props.projectPermissionsUpdated(this.props.project.id, selectedPermissions)
  }

  render () {
    let lookup = {}
    return (
      <Row style={{display: this.props.visible ? 'block' : 'none'}}>
        <Col xs={12}>
          <Row>
            <Col xs={12}>
              <ButtonGroup pullRight>
                <Button
                  active={this.props.settings.access === 'none'}
                  onClick={this.setAccess.bind(this, 'none')}
                >No Access</Button>

                <Button
                  active={this.props.settings.access === 'admin'}
                  onClick={this.setAccess.bind(this, 'admin')}
                >Admin</Button>

                <Button
                  active={this.props.settings.access === 'custom'}
                  onClick={this.setAccess.bind(this, 'custom')}
                >Custom</Button>
              </ButtonGroup>
            </Col>
          </Row>
          {this.props.settings.access === 'custom' ? (
            <Row>
              <Col xs={6}>

Feed Sources

                {this.props.project.feedSources ? this.props.project.feedSources.map((feed, i) => {
                  let name = (feed.name === '') ? '(unnamed feed)' : feed.name
                  let ref = 'feed-' + feed.id
                  let checked = this.props.settings.defaultFeeds.indexOf(feed.id) !== -1
                  return <Input
                    ref={ref}
                    type='checkbox'
                    defaultChecked={checked}
                    label={name}
                    onClick={this.feedsUpdated.bind(this)}
                  />
                }) : 'Cannot fetch feeds'
              }
              </Col>
              <Col xs={6}>

Permissions

                {allPermissions.map((permission, i) => {
                  let ref = 'permission-' + permission.type
                  let checked = this.props.settings.permissions.indexOf(permission.type) !== -1
                  return <Input
                    ref={ref}
                    type='checkbox'
                    defaultChecked={checked}
                    label={permission.name}
                    onClick={this.permissionsUpdated.bind(this)}
                  />
                })}
              </Col>
            </Row>
          ) : ''}
        </Col>
      </Row>
    )
  }
}
<commit_msg>Fix bug in admin UI project settings selector, add sorting<commit_after>import React from 'react'
import { Row, Col, Input, Panel, SplitButton, MenuItem, Label, ButtonGroup, Button } from 'react-bootstrap'
import update from 'react-addons-update'

import allPermissions from './permissions'

export default class UserSettings extends React.Component {

  constructor (props) {
    super(props)
    this.state = {
      appAdminChecked: this.props.permissions.isApplicationAdmin(),
      currentProjectIndex: 0,
      projectSettings: {},
    }

    this.props.projects.forEach((project, i) => {
      let access = 'none'
      let defaultFeeds = []
      let permissions = []
      if(this.props.permissions.hasProject(project.id)) {
        if(this.props.permissions.isProjectAdmin(project.id)) {
          access = 'admin'
        }
        else {
          access = 'custom'
          let projectPermissions = this.props.permissions.getProjectPermissions(project.id)
          permissions = projectPermissions.map((p) => { return p.type })
          defaultFeeds = this.props.permissions.getProjectDefaultFeeds(project.id)
        }
      }
      this.state.projectSettings[project.id] = { access, defaultFeeds, permissions }
    })
  }

  getSettings () {
    if(this.state.appAdminChecked) {
      return {
        permissions: [{
          type: 'administer-application'
        }],
        projects: []
      }
    }

    let settings = { permissions: [], projects: [] }

    this.props.projects.forEach((project, i) => {
      let stateProjectSettings = this.state.projectSettings[project.id]
      if (stateProjectSettings.access === 'none') return

      let projectSettings = {
        project_id: project.id,
        permissions: []
      }
      if (stateProjectSettings.access === 'admin') {
        projectSettings.permissions.push({
          type: 'administer-project'
        })
      } else if (stateProjectSettings.access === 'custom') {
        projectSettings.defaultFeeds = stateProjectSettings.defaultFeeds
        // users have view-all permissions by default
        projectSettings.permissions.push({
          type: 'view-feed',
          feeds: ['*']
        })
        projectSettings.permissions = projectSettings.permissions.concat(stateProjectSettings.permissions.map((permission) => {
          return { type: permission }
        }))
      }
      settings.projects.push(projectSettings)
    })

    return settings
  }

  projectSelected (key) {
    let currentProject = this.props.projects[key]
    this.setState({
      currentProjectIndex: key
    })
  }

  appAdminClicked () {
    this.setState({
      appAdminChecked: this.refs['appAdminCheckbox'].getChecked()
    })
  }

  projectAccessUpdated(projectId, newAccess) {
    var stateUpdate = { projectSettings: { [projectId]: { $merge : { access : newAccess } } } };
    this.setState(update(this.state, stateUpdate));
  }

  projectFeedsUpdated(projectId, newFeeds) {
    var stateUpdate = { projectSettings: { [projectId]: { $merge : { defaultFeeds : newFeeds } } } };
    this.setState(update(this.state, stateUpdate));
  }

  projectPermissionsUpdated(projectId, newPermissions) {
    var stateUpdate = { projectSettings: { [projectId]: { $merge : { permissions : newPermissions } } } };
    this.setState(update(this.state, stateUpdate));
  }

  render () {
    let currentProject = this.props.projects[this.state.currentProjectIndex]

    let projectPanel = (
      <Panel header={

          Project Settings for
          <SplitButton
            title={currentProject.name}
            onSelect={(key) => this.projectSelected(key)}
            pullRight
          >
            {this.props.projects.map((project, i) => {
              let settings = this.state.projectSettings[project.id]
              if (typeof settings !== 'undefined')
                return <MenuItem eventKey={i}>{project.name} {getProjectLabel(settings.access)}</MenuItem>
            })}
          </SplitButton>

      }
      >

      {this.props.projects.map((project, i) => {
        let settings = this.state.projectSettings[project.id]
        return <ProjectSettings
          project={project}
          settings={settings}
          fetchProjectFeeds={this.props.fetchProjectFeeds}
          visible={(i === this.state.currentProjectIndex)}
          projectAccessUpdated={this.projectAccessUpdated.bind(this)}
          projectFeedsUpdated={this.projectFeedsUpdated.bind(this)}
          projectPermissionsUpdated={this.projectPermissionsUpdated.bind(this)}
        />
      })}
    </Panel>)

    return (
      <Row>
        <Col xs={4}>
          <Panel header={
Application Settings
}>
            <Input
              type='checkbox'
              label='Application Administrator'
              defaultChecked={this.state.appAdminChecked}
              onClick={this.appAdminClicked.bind(this)}
              ref='appAdminCheckbox'
            />
          </Panel>
        </Col>
        <Col xs={8}>
          {this.state.appAdminChecked
            ? Application administrators have full access to all projects.
            : projectPanel
          }
        </Col>
      </Row>
    )
  }
}

function getProjectLabel(access) {
  switch(access) {
    case 'none': return None
    case 'admin': return Admin
    case 'custom': return Custom
  }
}

class ProjectSettings extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      projectSettings: this.props.settings
    }
  }
  static propTypes = {
    project: React.PropTypes.object.isRequired,
    settings: React.PropTypes.object.isRequired
  }
  componentWillMount () {
    if (!this.props.project.feedSources) {
      console.log('fetchingFeeds for ' + this.props.project.id)
      this.props.fetchProjectFeeds(this.props.project.id)
    }
  }
  setAccess (access) {
    console.log(access)
    this.props.projectAccessUpdated(this.props.project.id, access)
  }

  feedsUpdated () {
    let selectedFeeds = []
    this.props.project.feedSources.forEach((feed) => {
      var checkbox = this.refs['feed-' + feed.id]
      if(checkbox.getChecked()) selectedFeeds.push(feed.id)
    })
    this.props.projectFeedsUpdated(this.props.project.id, selectedFeeds)
  }

  permissionsUpdated () {
    let selectedPermissions = []
    allPermissions.forEach((permission) => {
      var checkbox = this.refs['permission-' + permission.type]
      if(checkbox.getChecked()) selectedPermissions.push(permission.type)
    })
    this.props.projectPermissionsUpdated(this.props.project.id, selectedPermissions)
  }

  render () {
    let lookup = {}

    let feedSources = this.props.project.feedSources
    if (feedSources) {
      feedSources = feedSources.slice(0).sort((a, b) => {
        if (a.name  b.name) return 1
        return 0
      })
    }

    return (
      <Row style={{display: this.props.visible ? 'block' : 'none'}}>
        <Col xs={12}>
          <Row>
            <Col xs={12}>
              <ButtonGroup pullRight>
                <Button
                  active={this.props.settings.access === 'none'}
                  onClick={this.setAccess.bind(this, 'none')}
                >No Access</Button>

                <Button
                  active={this.props.settings.access === 'admin'}
                  onClick={this.setAccess.bind(this, 'admin')}
                >Admin</Button>

                <Button
                  active={this.props.settings.access === 'custom'}
                  onClick={this.setAccess.bind(this, 'custom')}
                >Custom</Button>
              </ButtonGroup>
            </Col>
          </Row>
          {this.props.settings.access === 'custom' ? (
            <Row>
              <Col xs={6}>

Feed Sources

                {feedSources ? feedSources.map((feed, i) => {
                  let name = (feed.name === '') ? '(unnamed feed)' : feed.name
                  let ref = 'feed-' + feed.id
                  let checked = this.props.settings.defaultFeeds.indexOf(feed.id) !== -1
                  return <Input
                    ref={ref}
                    type='checkbox'
                    defaultChecked={checked}
                    label={name}
                    onClick={this.feedsUpdated.bind(this)}
                  />
                }) : 'Cannot fetch feeds'
              }
              </Col>
              <Col xs={6}>

Permissions

                {allPermissions.map((permission, i) => {
                  let ref = 'permission-' + permission.type
                  let checked = this.props.settings.permissions.indexOf(permission.type) !== -1
                  return <Input
                    ref={ref}
                    type='checkbox'
                    defaultChecked={checked}
                    label={permission.name}
                    onClick={this.permissionsUpdated.bind(this)}
                  />
                })}
              </Col>
            </Row>
          ) : ''}
        </Col>
      </Row>
    )
  }
}
<|endoftext|>


<commit_before>'use strict';

const client_id = process.env.CLIENT_ID;
const client_secret = process.env.CLIENT_SECRET;
const request = require('request');
const Manager = require('../model/manager');
let user_id;

module.exports = function(req, res, next) {

  let time = Date.now();
  let manager = res.manager;
  user_id = manager.username;

  let authOptions = {
    url: 'https://accounts.spotify.com/api/token',
    headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
    form: {
      grant_type: 'refresh_token',
      refresh_token: manager.refreshToken
    },
    json: true
  };

  let getToken = (function(next) {
    return getNewToken;
  })(next);

  if (manager.tokenExpires < time) {
    request.post(authOptions, getToken);
  } else next();
};

function getNewToken(err, res, body) {
  console.log('request new token');
  if (!err && res.statusCode === 200) {
    let expires_in = body.expires_in * 1000;
    let access_token = body.access_token;

    Manager.findOneAndUpdate({username: user_id}, { $set: {accessToken: access_token, tokenExpires: expires_in + Date.now()}}, {new: true}, (err, manager) => {
      if (err) throw err;
      res.manager = manager;
      next();
    });

  }
}
<commit_msg>fixed lint errors<commit_after>'use strict';

const client_id = process.env.CLIENT_ID;
const client_secret = process.env.CLIENT_SECRET;
const request = require('request');
const Manager = require('../model/manager');
let user_id;

module.exports = function(req, res, next) {

  let time = Date.now();
  let manager = res.manager;
  user_id = manager.username;

  let authOptions = {
    url: 'https://accounts.spotify.com/api/token',
    headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
    form: {
      grant_type: 'refresh_token',
      refresh_token: manager.refreshToken
    },
    json: true
  };

  let getToken = (function() {
    return getNewToken;
  })(next);

  if (manager.tokenExpires < time) {
    request.post(authOptions, getToken);
  } else next();
};

function getNewToken(err, res, body) {
  console.log('request new token');
  if (!err && res.statusCode === 200) {
    let expires_in = body.expires_in * 1000;
    let access_token = body.access_token;

    Manager.findOneAndUpdate({username: user_id}, { $set: {accessToken: access_token, tokenExpires: expires_in + Date.now()}}, {new: true}, (err, manager) => {
      if (err) throw err;
      res.manager = manager;
      // next();
    });

  }
}
<|endoftext|>


<commit_before>/* global require */
var http = require('http');
var fs = require('fs');
var path = require('path');
var express = require('express');
var path = require('path');
var app = express();
var cons = require('consolidate');
var reducedir = require('reduce-dir');

app.set('port', process.env.PORT || 3001);

app.engine('hbs', cons.handlebars);
app.set('view engine', 'hbs');

app.get('/exampletemplate', function(res, res) {
  res.render('example', {
    data: 'hello'
  });
});

// Allow reading the files directly. express.directory and express.static
// work together to make a file browser
app.use('/raw', express.directory('api'));
app.use('/raw', express.static('api'));

// Serve static assets
app.use('/', express.static(path.join(__dirname, '/public/app')));

// Routes for serving our HTML pages
app.get('/', function(req, res) {
  res.sendfile('public/app/base.html');
});
app.get('/chapters/:chapterName', function(req, res) {
  res.sendfile('public/app/base.html');
});
app.get('/chapters', function(req, res) {
  res.sendfile('public/app/base.html');
});

app.get('/api/*', function(req, res) {
  generic_handler(req, res, 'api/'+req.params.join('/'));
});

function sanitize(req, res, next) {
  for (var key in req.params) {
    if (req.params[key].indexOf(".") > -1) {
      return res.json(400, "Bad request");
    }
  }
  next();
}

function generic_handler(req, res, dirpath) {

  function callback(err, files) {
    if (err) {
      return notFound(err, res);
    }
    //
    // Validate the files are json before we try and load them
    //
    var root = path.join(__dirname, dirpath);
    var data  = files.filter(function (file) {
      return /.json$/.test(file);
    }).map(function (file) {
      var d;
      try { d = require(path.join(root, file)); }
      catch (ex) { d = null; }
      return d;
    }).filter(Boolean);

    var submodules = files.filter(function (file) {
      return fs.statSync(path.join(root, file)).isDirectory(); // TODO make async
    });

    var _files = files.filter(function (file) {
      return fs.statSync(path.join(root, file)).isFile(); // TODO make async
    });

    res.json(200, {'module':path.basename(root), path:path.relative(__dirname, path.dirname(root)), data: data, submodules:submodules, files:_files});
  }

  fs.readdir(dirpath, callback);
}

function notFound(err, res) {
  //
  // TODO: send better error responses
  //
  res.writeHead(500, { 'content-type': 'application/json' });
  return res.end(JSON.stringify({ error: err.message, reason: 'invalid parameters'}));
}

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>Adding a route to handle this because it was frustrating me.<commit_after>/* global require */
var http = require('http');
var fs = require('fs');
var path = require('path');
var express = require('express');
var path = require('path');
var app = express();
var cons = require('consolidate');
var reducedir = require('reduce-dir');

app.set('port', process.env.PORT || 3001);

app.engine('hbs', cons.handlebars);
app.set('view engine', 'hbs');

app.get('/exampletemplate', function(res, res) {
  res.render('example', {
    data: 'hello'
  });
});

// Allow reading the files directly. express.directory and express.static
// work together to make a file browser
app.use('/raw', express.directory('api'));
app.use('/raw', express.static('api'));

// Serve static assets
app.use('/', express.static(path.join(__dirname, '/public/app')));

// Routes for serving our HTML pages
app.get('/', function(req, res) {
  res.sendfile('public/app/base.html');
});
app.get('/chapters/:chapterName', function(req, res) {
  res.sendfile('public/app/base.html');
});
app.get('/chapters/:chapterName/:submoduleName', function(req, res) {
  res.sendfile('public/app/base.html');
});
app.get('/chapters', function(req, res) {
  res.sendfile('public/app/base.html');
});

app.get('/api/*', function(req, res) {
  generic_handler(req, res, 'api/'+req.params.join('/'));
});

function sanitize(req, res, next) {
  for (var key in req.params) {
    if (req.params[key].indexOf(".") > -1) {
      return res.json(400, "Bad request");
    }
  }
  next();
}

function generic_handler(req, res, dirpath) {

  function callback(err, files) {
    if (err) {
      return notFound(err, res);
    }
    //
    // Validate the files are json before we try and load them
    //
    var root = path.join(__dirname, dirpath);
    var data  = files.filter(function (file) {
      return /.json$/.test(file);
    }).map(function (file) {
      var d;
      try { d = require(path.join(root, file)); }
      catch (ex) { d = null; }
      return d;
    }).filter(Boolean);

    var submodules = files.filter(function (file) {
      return fs.statSync(path.join(root, file)).isDirectory(); // TODO make async
    });

    var _files = files.filter(function (file) {
      return fs.statSync(path.join(root, file)).isFile(); // TODO make async
    });

    res.json(200, {'module':path.basename(root), path:path.relative(__dirname, path.dirname(root)), data: data, submodules:submodules, files:_files});
  }

  fs.readdir(dirpath, callback);
}

function notFound(err, res) {
  //
  // TODO: send better error responses
  //
  res.writeHead(500, { 'content-type': 'application/json' });
  return res.end(JSON.stringify({ error: err.message, reason: 'invalid parameters'}));
}

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>var log = require ('./logging.js');

// =============================================================================
// CHUNK SENDER
// This module is responsible for sending chunks to the user.
// =============================================================================

// Constants ==================================================================
var DEFAULT_RATE = 120;

// Class =======================================================================
function ChunkSender (frameRate_) {
	log = log.logger;

	this._socket = undefined;               // Connection to client

	this._configChunk = undefined;          // Most recent config chunk
	this._frameQueue = [];                  // Unhandled frame chunks

	frameRate_ = frameRate_ || DEFAULT_RATE;

	this._started = false;                  // Whether or not we've started
	this._interval = 1000 / frameRate_;     // How frequently to send frames
	this._lastFrame = undefined;            // When we send the last frame
	this._accumulator = 0;                  // 'Extra' time
}

// Private functions ===========================================================
// If a client is connected, send a chunk
ChunkSender.prototype._sendChunk = function (chunk_) {
	console.assert (this instanceof ChunkSender);
	console.assert (chunk_ !== undefined);

	if (this._socket === undefined)
		return;

	function throwError (msg) {
		if (msg)
			throw new Error (msg);
	}

	for (var i in chunk_) {
		this._socket.send (chunk_[i], throwError);
	}
};

// This function makes sure that we send frames as close to the specified rate
// as possible.
//
// Suppose the user specifies a rate of 10. So we should be sending
// a frame every 100ms. Unfortunately, Javascript can't guarantee that this
// function will be called in exactly 100ms. Suppose it's called in 102ms.
// So 102ms has elapsed, but we're supposed to send a frame every 100ms. Well,
// we see that enough time has elapsed for us to send 1 frame, so we do. That
// leaves 2ms unaccounted for, though, so those are added to an accumulator.
// Now suppose on the next go round the function is called in 98ms. Normally,
// that's not enough time to send a new frame, but we have those 2ms left over
// so we add those in to get 100ms and we can send a new frame. Our accumulator
// is then set back to 0.
ChunkSender.prototype._sendFrame = function () {
	console.assert (this instanceof ChunkSender);

	var time = Date.now ();
	var diff = this._interval || time - this._lastFrame;

	// This is the total amount of time that hasn't been accounted for
	var total = diff + this._accumulator;
	var rem = total % this._interval;
	var frames = Math.min ((total - rem) / this._interval, this._frameQueue.length);

	// Enough time has elapsed that we should send a frame
	if (frames !== 0) {
		this._accumulator = rem;
		this._lastFrame = time;

		// If we should send n frames, we're only going to send the nth one
		// so we can forget about the first n-1 unsent frames
		this._frameQueue.splice (0, frames-1);

		this._sendChunk (this._frameQueue.shift ());
	}

	// Timer to send the next frame
	setTimeout (this._sendFrame.bind (this), this._interval);
};

// Public functions ============================================================
ChunkSender.prototype.setSocket = function (socket_) {
	console.assert (this instanceof ChunkSender);

	this._socket = socket_;
	this._sendChunk (this._configChunk);
};

ChunkSender.prototype.handleConfigChunk = function (configChunk_) {
	console.assert (this instanceof ChunkSender);

	this._configChunk = configChunk_;
	this._sendChunk (this._configChunk);
};

ChunkSender.prototype.handleFrameChunk = function (frameChunk_) {
	console.assert (this instanceof ChunkSender);

	this._frameQueue.push (frameChunk_);

	if (!this._started) {
		this._started = true;
		this._sendFrame ();
	}
};

module.exports = ChunkSender;

<commit_msg>Only try to send config chunk if we've gotten one<commit_after>var log = require ('./logging.js');

// =============================================================================
// CHUNK SENDER
// This module is responsible for sending chunks to the user.
// =============================================================================

// Constants ==================================================================
var DEFAULT_RATE = 120;

// Class =======================================================================
function ChunkSender (frameRate_) {
	log = log.logger;

	this._socket = undefined;               // Connection to client

	this._configChunk = undefined;          // Most recent config chunk
	this._frameQueue = [];                  // Unhandled frame chunks

	frameRate_ = frameRate_ || DEFAULT_RATE;

	this._started = false;                  // Whether or not we've started
	this._interval = 1000 / frameRate_;     // How frequently to send frames
	this._lastFrame = undefined;            // When we send the last frame
	this._accumulator = 0;                  // 'Extra' time
}

// Private functions ===========================================================
// If a client is connected, send a chunk
ChunkSender.prototype._sendChunk = function (chunk_) {
	console.assert (this instanceof ChunkSender);
	console.assert (chunk_ !== undefined);

	if (this._socket === undefined)
		return;

	function throwError (msg) {
		if (msg)
			throw new Error (msg);
	}

	for (var i in chunk_) {
		this._socket.send (chunk_[i], throwError);
	}
};

// This function makes sure that we send frames as close to the specified rate
// as possible.
//
// Suppose the user specifies a rate of 10. So we should be sending
// a frame every 100ms. Unfortunately, Javascript can't guarantee that this
// function will be called in exactly 100ms. Suppose it's called in 102ms.
// So 102ms has elapsed, but we're supposed to send a frame every 100ms. Well,
// we see that enough time has elapsed for us to send 1 frame, so we do. That
// leaves 2ms unaccounted for, though, so those are added to an accumulator.
// Now suppose on the next go round the function is called in 98ms. Normally,
// that's not enough time to send a new frame, but we have those 2ms left over
// so we add those in to get 100ms and we can send a new frame. Our accumulator
// is then set back to 0.
ChunkSender.prototype._sendFrame = function () {
	console.assert (this instanceof ChunkSender);

	var time = Date.now ();
	var diff = this._interval || time - this._lastFrame;

	// This is the total amount of time that hasn't been accounted for
	var total = diff + this._accumulator;
	var rem = total % this._interval;
	var frames = Math.min ((total - rem) / this._interval, this._frameQueue.length);

	// Enough time has elapsed that we should send a frame
	if (frames !== 0) {
		this._accumulator = rem;
		this._lastFrame = time;

		// If we should send n frames, we're only going to send the nth one
		// so we can forget about the first n-1 unsent frames
		this._frameQueue.splice (0, frames-1);

		this._sendChunk (this._frameQueue.shift ());
	}

	// Timer to send the next frame
	setTimeout (this._sendFrame.bind (this), this._interval);
};

// Public functions ============================================================
ChunkSender.prototype.setSocket = function (socket_) {
	console.assert (this instanceof ChunkSender);

	this._socket = socket_;

	if (this._configChunk !== undefined)
		this._sendChunk (this._configChunk);
};

ChunkSender.prototype.handleConfigChunk = function (configChunk_) {
	console.assert (this instanceof ChunkSender);

	this._configChunk = configChunk_;
	this._sendChunk (this._configChunk);
};

ChunkSender.prototype.handleFrameChunk = function (frameChunk_) {
	console.assert (this instanceof ChunkSender);

	this._frameQueue.push (frameChunk_);

	if (!this._started) {
		this._started = true;
		this._sendFrame ();
	}
};

module.exports = ChunkSender;

<|endoftext|>


<commit_before>function (user, context, callback) {
  var jwt  = require("jsonwebtoken");
  var CLIENTS_WITH_MFA = ['{REPLACE_WITH_YOUR_CLIENT_ID}'];

  // run only for the specified clients
  if (CLIENTS_WITH_MFA.indexOf(context.clientID) === -1) {
    return callback(null,user,context);
  }

  // returning from MFA validation
  if(context.protocol === 'redirect-callback') {
    var decoded = jwt.verify(context.request.query.id_token, new Buffer(configuration.slack_mfa_secret, 'base64'));
    if (!decoded || decoded.issuer !== 'urn:sgmeyer:slack:mfacallback') return callback(new Error('Invalid Token'));

    return callback(null, user, context);
  } else {
    var uuid = require('uuid');
    var token_payload = { jti: uuid.v4() };
    if (user.user_metadata) {
      token_payload = {
        slack_username: user.user_metadata.slack_mfa_username,
        slack_enrolled:  user.user_metadata.slack_mfa_enrolled,
        jti: uuid.v4()
      };
    }

    var token = jwt.sign(token_payload,
      new Buffer(configuration.slack_mfa_secret, 'base64'),
      {
        subject: user.user_id,
        expiresInMinutes: 5,
        audience: context.clientID,
        issuer: 'urn:sgmeyer:slack:mfa',
        iat: new Date().getTime() / 1000,
      });

    //Trigger MFA
    context.redirect = { url: configuration.slack_mfa_url + '?token=' + token };
    callback(null, user, context);
  }
}
<commit_msg>Letting the rule decide if it should send the DM or start enrollment<commit_after>function (user, context, callback) {
  var jwt  = require("jsonwebtoken");
  var CLIENTS_WITH_MFA = ['{REPLACE_WITH_YOUR_CLIENT_ID}'];

  // run only for the specified clients
  if (CLIENTS_WITH_MFA.indexOf(context.clientID) === -1) {
    return callback(null,user,context);
  }

  // returning from MFA validation
  if(context.protocol === 'redirect-callback') {
    var decoded = jwt.verify(context.request.query.id_token, new Buffer(configuration.slack_mfa_secret, 'base64'));
    if (!decoded || decoded.issuer !== 'urn:sgmeyer:slack:mfacallback') return callback(new Error('Invalid Token'));

    return callback(null, user, context);
  } else {
    var uuid = require('uuid');
    var token_payload = { jti: uuid.v4() };
    if (user.user_metadata) {
      token_payload = {
        slack_username: user.user_metadata.slack_mfa_username,
        slack_enrolled:  user.user_metadata.slack_mfa_enrolled,
        jti: uuid.v4()
      };
    }

    var token = jwt.sign(token_payload,
      new Buffer(configuration.slack_mfa_secret, 'base64'),
      {
        subject: user.user_id,
        expiresInMinutes: 5,
        audience: context.clientID,
        issuer: 'urn:sgmeyer:slack:mfa',
        iat: new Date().getTime() / 1000,
      });

    //Trigger MFA
    var route = user.user_metadata.slack_mfa_username ? "/mfa" : "/enroll";
    context.redirect = { url: configuration.slack_mfa_url + route + '?token=' + token };
    callback(null, user, context);
  }
}
<|endoftext|>


<commit_before>/**
 * @author Titus Wormer
 * @copyright 2015 Titus Wormer. All rights reserved.
 * @module Program
 * @fileoverview Bridge between CLI options and node.
 */

'use strict';

/*
 * Dependencies.
 */

var commander = require('commander');
var camelcase = require('camelcase');
var debug = require('debug');
var pack = require('../../package.json');

/*
 * Methods.
 */

var Command = commander.Command;

/*
 * Constants.
 */

var SPLITTER = / *[,;] */g;

/*
 * Set-up.
 */

var COMMAND = Object.keys(pack.bin)[0];

debug = debug('mdast:cli-program');

/**
 * Parse a (lazy?) JSON config.
 *
 * @param {string} value
 * @return {Object} - Parsed `value`.
 * @throws {Error} - When the augmented options could not
 *   be parsed.
 */
function parseJSON(value) {
    /*
     * Quote unquoted property keys.
     */

    value = value.replace(/([a-zA-Z0-9\-\/]+)(?=\s*:)/g, '\"$&\"');

    return JSON.parse('{' + value + '}');
}

/**
 * Transform the keys on an object to camel-case,
 * recursivly.
 *
 * @example
 *   toCamelCase({"foo-bar": {"qux-quux": "baz"}});
 *   // {"fooBar": {"quxQuux": "baz"}}
 *
 * @param {Object} object - Object to transform.
 * @return {Object} - New object, with camel-case keys.
 */
function toCamelCase(object) {
    var result = {};
    var value;
    var key;

    for (key in object) {
        value = object[key];

        if (value && typeof value === 'object' && !('length' in value)) {
            value = toCamelCase(value);
        }

        result[camelcase(key)] = value;
    }

    return result;
}

/**
 * Parse settings into an object.
 *
 * @example
 *   var cache = {};
 *   options('commonmark: true', cache);
 *
 * @param {string} flags - Command line settings.  These
 *   are just JSON, although the keys do not need double
 *   quotes to work.
 * @param {Object} cache - Settings store.
 * @return {Object} - `cache`.
 */
function options(flags, cache) {
    var flag;

    try {
        flags = toCamelCase(parseJSON(flags));
    } catch (exception) {
        exception.message = 'Cannot parse CLI settings: \nError: ' +
            exception.message;

        throw exception;
    }

    for (flag in flags) {
        cache[flag] = flags[flag];
    }

    return cache;
}

/**
 * Parse a plugin into its name and options.
 *
 * @example
 *   var plugin = parsePlugin('mdast-toc=heading:"foo"');
 *
 * @param {string} plugin - Plugin name with options.
 * @return {Object}
 */
function parsePlugin(plugin) {
    var index = plugin.indexOf('=');
    var name;
    var value;

    if (index === -1) {
        name = plugin;
        value = null;
    } else {
        name = plugin.slice(0, index);
        value = options(plugin.slice(index + 1), {});
    }

    return {
        'name': name,
        'value': value
    };
}

/**
 * Parse plugins into a list.
 *
 * @example
 *   var cache = {};
 *   plugins('foo=bar:false', cache);
 *
 * @param {string} plugin - Plugin name with options.
 * @param {Object} cache - Plugin store.
 * @return {Object} - `cache`.
 */
function plugins(plugin, cache) {
    plugin = parsePlugin(plugin);

    cache[plugin.name] = plugin.value;

    return cache;
}

/**
 * Parse extensions into a list.
 *
 * @example
 *   var res = extensions('markdown,ron', ['md']);
 *
 * @param {string} extension - List of extensions.
 * @param {Array.<string>} cache - Extension store.
 * @return {Array.<string>} - New extensions store.
 */
function extensions(extension, cache) {
    return cache.concat(extension.split(SPLITTER));
}

/**
 * Help.
 */
function help() {
    console.log('  Usage:');
    console.log();
    console.log('  # Pass `readme.md` through mdast');
    console.log('  $ ' + COMMAND + ' readme.md -o readme-new.md');
    console.log();
    console.log('  # Pass stdin through mdast, with settings, to stdout');
    console.log('  $ cat readme.md | ' + COMMAND + ' -s "setext: true, ' +
        'bullet: \"*\"" > readme-new.md');
    console.log();
    console.log('  # Use a plugin (with options)');
    console.log('  $ npm install mdast-toc');
    console.log('  $ ' + COMMAND + ' --use toc=heading:"contents" ' +
        'readme.md -o');
    console.log();
    console.log('  # Rewrite markdown in a directory');
    console.log('  $ ' + COMMAND + ' . -o');
    console.log();
    console.log('  See also:');
    console.log();
    console.log('  man 1 mdast, man 3 mdast, man 5 mdastrc, ' +
        'man 5 mdastignore, man 7 mdastconfig');
    console.log();
}

/*
 * Module.
 */

var program = new Command(pack.name)
    .version(pack.version)
    .description(pack.description)
    .usage('[options] file|dir ...')
    .option('-o, --output [path]', 'specify output location')
    .option('-c, --config-path <path>', 'specify configuration location')
    .option('-i, --ignore-path <path>', 'specify ignore location')
    .option('-s, --setting <settings>', 'specify settings', options, {})
    .option('-u, --use <plugins>', 'use transform plugin(s)', plugins, {})
    .option('-e, --ext <extensions>', 'specify extensions', extensions, [])
    .option('-a, --ast', 'output AST information', false)
    .option('-q, --quiet', 'output only warnings and errors', false)
    .option('-S, --silent', 'output only errors', false)
    .option('--file-path <path>', 'specify file path to process as', false)
    .option('--no-color', 'disable color in output', false)
    .option('--no-rc', 'disable configuration from .mdastrc', false)
    .option('--no-ignore', 'disable ignore from .mdastignore', false);

/*
 * Listen.
 */

program.on('--help', help);

/*
 * Expose.
 */

module.exports = program;
<commit_msg>Add example to `parseJSON` jsdoc documentation<commit_after>/**
 * @author Titus Wormer
 * @copyright 2015 Titus Wormer. All rights reserved.
 * @module Program
 * @fileoverview Bridge between CLI options and node.
 */

'use strict';

/*
 * Dependencies.
 */

var commander = require('commander');
var camelcase = require('camelcase');
var debug = require('debug');
var pack = require('../../package.json');

/*
 * Methods.
 */

var Command = commander.Command;

/*
 * Constants.
 */

var SPLITTER = / *[,;] */g;

/*
 * Set-up.
 */

var COMMAND = Object.keys(pack.bin)[0];

debug = debug('mdast:cli-program');

/**
 * Parse a (lazy?) JSON config.
 *
 * @example
 *   parseJSON('foo:true') // {'foo': true}
 *
 *   parseJSON('foo-bar: 1, baz-qux: -1') // {'foo-bar': 1, baz-qux: -1}
 *
 *   parseJSON('foo: ["bar", "baz"]') // {'foo': ['bar', 'baz']}
 *
 * @param {string} value
 * @return {Object} - Parsed `value`.
 * @throws {Error} - When the augmented options could not
 *   be parsed.
 */
function parseJSON(value) {
    /*
     * Quote unquoted property keys.
     */

    value = value.replace(/([a-zA-Z0-9\-\/]+)(?=\s*:)/g, '\"$&\"');

    return JSON.parse('{' + value + '}');
}

/**
 * Transform the keys on an object to camel-case,
 * recursivly.
 *
 * @example
 *   toCamelCase({"foo-bar": {"qux-quux": "baz"}});
 *   // {"fooBar": {"quxQuux": "baz"}}
 *
 * @param {Object} object - Object to transform.
 * @return {Object} - New object, with camel-case keys.
 */
function toCamelCase(object) {
    var result = {};
    var value;
    var key;

    for (key in object) {
        value = object[key];

        if (value && typeof value === 'object' && !('length' in value)) {
            value = toCamelCase(value);
        }

        result[camelcase(key)] = value;
    }

    return result;
}

/**
 * Parse settings into an object.
 *
 * @example
 *   var cache = {};
 *   options('commonmark: true', cache);
 *
 * @param {string} flags - Command line settings.  These
 *   are just JSON, although the keys do not need double
 *   quotes to work.
 * @param {Object} cache - Settings store.
 * @return {Object} - `cache`.
 */
function options(flags, cache) {
    var flag;

    try {
        flags = toCamelCase(parseJSON(flags));
    } catch (exception) {
        exception.message = 'Cannot parse CLI settings: \nError: ' +
            exception.message;

        throw exception;
    }

    for (flag in flags) {
        cache[flag] = flags[flag];
    }

    return cache;
}

/**
 * Parse a plugin into its name and options.
 *
 * @example
 *   var plugin = parsePlugin('mdast-toc=heading:"foo"');
 *
 * @param {string} plugin - Plugin name with options.
 * @return {Object}
 */
function parsePlugin(plugin) {
    var index = plugin.indexOf('=');
    var name;
    var value;

    if (index === -1) {
        name = plugin;
        value = null;
    } else {
        name = plugin.slice(0, index);
        value = options(plugin.slice(index + 1), {});
    }

    return {
        'name': name,
        'value': value
    };
}

/**
 * Parse plugins into a list.
 *
 * @example
 *   var cache = {};
 *   plugins('foo=bar:false', cache);
 *
 * @param {string} plugin - Plugin name with options.
 * @param {Object} cache - Plugin store.
 * @return {Object} - `cache`.
 */
function plugins(plugin, cache) {
    plugin = parsePlugin(plugin);

    cache[plugin.name] = plugin.value;

    return cache;
}

/**
 * Parse extensions into a list.
 *
 * @example
 *   var res = extensions('markdown,ron', ['md']);
 *
 * @param {string} extension - List of extensions.
 * @param {Array.<string>} cache - Extension store.
 * @return {Array.<string>} - New extensions store.
 */
function extensions(extension, cache) {
    return cache.concat(extension.split(SPLITTER));
}

/**
 * Help.
 */
function help() {
    console.log('  Usage:');
    console.log();
    console.log('  # Pass `readme.md` through mdast');
    console.log('  $ ' + COMMAND + ' readme.md -o readme-new.md');
    console.log();
    console.log('  # Pass stdin through mdast, with settings, to stdout');
    console.log('  $ cat readme.md | ' + COMMAND + ' -s "setext: true, ' +
        'bullet: \"*\"" > readme-new.md');
    console.log();
    console.log('  # Use a plugin (with options)');
    console.log('  $ npm install mdast-toc');
    console.log('  $ ' + COMMAND + ' --use toc=heading:"contents" ' +
        'readme.md -o');
    console.log();
    console.log('  # Rewrite markdown in a directory');
    console.log('  $ ' + COMMAND + ' . -o');
    console.log();
    console.log('  See also:');
    console.log();
    console.log('  man 1 mdast, man 3 mdast, man 5 mdastrc, ' +
        'man 5 mdastignore, man 7 mdastconfig');
    console.log();
}

/*
 * Module.
 */

var program = new Command(pack.name)
    .version(pack.version)
    .description(pack.description)
    .usage('[options] file|dir ...')
    .option('-o, --output [path]', 'specify output location')
    .option('-c, --config-path <path>', 'specify configuration location')
    .option('-i, --ignore-path <path>', 'specify ignore location')
    .option('-s, --setting <settings>', 'specify settings', options, {})
    .option('-u, --use <plugins>', 'use transform plugin(s)', plugins, {})
    .option('-e, --ext <extensions>', 'specify extensions', extensions, [])
    .option('-a, --ast', 'output AST information', false)
    .option('-q, --quiet', 'output only warnings and errors', false)
    .option('-S, --silent', 'output only errors', false)
    .option('--file-path <path>', 'specify file path to process as', false)
    .option('--no-color', 'disable color in output', false)
    .option('--no-rc', 'disable configuration from .mdastrc', false)
    .option('--no-ignore', 'disable ignore from .mdastignore', false);

/*
 * Listen.
 */

program.on('--help', help);

/*
 * Expose.
 */

module.exports = program;
<|endoftext|>


<commit_before>/*eslint indent:0*/
var
  _ = require('lodash'),
  util = require('util'),
  moment = require('moment'),
  path = require('path'),

  log = require('fedtools-logs'),
  config = require('fedtools-config'),

  common = require('../common'),

  EnvtoolsBase = require('./base'),
  EnvtoolsVersion;

// -- C O N S T R U C T O R

EnvtoolsVersion = function () {
  EnvtoolsBase.call(this);
};

// -- I N H E R I T A N C E

util.inherits(EnvtoolsVersion, EnvtoolsBase);
EnvtoolsVersion.prototype.name = 'EnvtoolsVersion';

// -- E X T E N D E D  M E T H O D S

EnvtoolsVersion.prototype._initialize = function () {
  var
    rcInfo,
    canCheck = false,
    needToCheck = false;

  EnvtoolsBase.prototype._initialize.call(this);

  // check for current version
  this.currentVersion = this.packageJson.version;

  // checking if the version was already benn checked recently
  rcInfo = this._getConfiguration();
  if (rcInfo && rcInfo[common.ENVTOOLS.CFG_AUTOCHECK] === common.ON) {
    canCheck = true;
  }
  if (canCheck && rcInfo && rcInfo.expiration) {
    // all the keys are here, let's check the expiration
    if (moment().isAfter(rcInfo.expiration)) {
      // time's out, need to check if there is a new version
      // Spawn a detached process that will update the key 'version'
      // from the .fedtoolsrc file with the following sub-keys:
      // version: {
      //   expiration: Now + 1d
      //   latest: x.y.z
      // }
      // It's non-blocking so the next time envtools run, just
      // checking the .fedtoolsrc file is enough.
      needToCheck = true;
    }
  } else {
    needToCheck = canCheck;
  }

  if (needToCheck) {
    require('child_process')
      .spawn(process.execPath, [path.join(__dirname, '..', '..', 'bin', 'check.js')], {
        detached: true,
        stdio: 'ignore'
      }).unref();
  }
};

// -- P R I V A T E  M E T H O D S
EnvtoolsVersion.prototype._getConfiguration = function () {
  return config.getKey('envtoolsversion');
};

// -- P U B L I C  M E T H O D S

EnvtoolsVersion.prototype.setAutoCheck = function (flag) {
  var
    o = {};
  o[common.ENVTOOLS.CFG_AUTOCHECK] = flag;
  config.setKey('envtoolsversion', _.extend(this._getConfiguration(), o), true, true);
};

EnvtoolsVersion.prototype.getAutoCheck = function () {
  var
    cfg = this._getConfiguration();

  if (cfg) {
    return (cfg[common.ENVTOOLS.CFG_AUTOCHECK]) ? cfg[common.ENVTOOLS.CFG_AUTOCHECK] : common.OFF;
  } else {
    return common.OFF;
  }
};

/**
 * This method will read the .fedtoolrc configuration file.
 * It will then display the 'update available' box if the one of
 * the following is true:
 * 1) cfg.alreadyDisplayed is falsy and cfg.latest is truthy
 * 2) force is true and cfg.latest is truthy
 * If it does, it will also update the configuration file to mark
 * that the message has been displayed to the user. (no need to
 * display it again. This flag will be removed automatically after
 * one day).
 *
 * @method printUpgradeIfAny
 * @param  {Boolean} force If true, ignore the 'alreadyDisplayed' key
 */
EnvtoolsVersion.prototype.printUpgradeIfAny = function (force) {
  var
    self = this,
    msg = [],
    lightGrey = 245,
    rcInfo = this._getConfiguration() || {},
    LATEST_IS_INSTALLED = 'You are up-to-date!',
    NO_DATA_AVAILABLE = 'There is no data available at this time.\nPlease check again later...',
    AUTOCHECK_DISABLED = 'Automatically check for update is disabled.\nYou can enable this option by typing ' +
    log.strToColor(lightGrey, 'envtools config') +
    '\nand following the instructions at the prompt.';

  function printCustomMessage(msgs, boxColor) {
    log.echo();
    log.printMessagesInBox(msgs, (boxColor) ? boxColor : 'yellow');
    log.echo();
    return true;
  }

  if (force && !rcInfo) {
    return printCustomMessage([NO_DATA_AVAILABLE]);
  }

  if (force && rcInfo[common.ENVTOOLS.CFG_AUTOCHECK] !== common.ON) {
    return printCustomMessage([AUTOCHECK_DISABLED]);
  }

  if (rcInfo.latest) {
    if (require('semver').gt(rcInfo.latest, self.currentVersion)) {
      msg.push('');
      msg.push('A new version of Envtools has been published!');
      msg.push('Envtools ' +
        log.strToColor('green', rcInfo.latest) +
        ' is now available - you have ' +
        log.strToColor(lightGrey, self.currentVersion));
      msg.push('Type ' +
        log.strToColor(lightGrey, 'npm install -g envtools') +
        ' to upgrade.');
      msg.push('');
    } else {
      msg.push('');
      msg.push(LATEST_IS_INSTALLED + ' (' + self.currentVersion + ')');
      msg.push('');
    }
  } else {
    return printCustomMessage([NO_DATA_AVAILABLE]);
  }

  if (msg.length && (!rcInfo.alreadyDisplayed || force)) {
    // need to mark version as displayed so that it won't
    // be shown to the user again (until the expiration date)
    config.setKey('envtoolsversion', _.extend(rcInfo, {
      alreadyDisplayed: true
    }), true, true);

    return printCustomMessage(msg, 'green');
  }
};

/**
 * This method is supposed to be called explicitely by the user (for
 * example, envtools -v). In that case, we assume that we can present
 * the current version, but also the 'update available' message.
 *
 * @method printCurrentVersion
 */
EnvtoolsVersion.prototype.printCurrentVersion = function (boring, done) {
  if (!this.printUpgradeIfAny()) {
    log.echo();
    log.printMessagesInBox([
      '',
      this.i18n.t('version.installed') + log.strToColor('green', this.currentVersion),
      ''
    ]);
    log.echo();
  }
  done();
};

// -- E X P O R T S
module.exports = (function () {
  return EnvtoolsVersion._instance || new EnvtoolsVersion();
})();
<commit_msg>Fixing version up-to-date message appearing unexpected<commit_after>/*eslint indent:0*/
var
  _ = require('lodash'),
  util = require('util'),
  moment = require('moment'),
  path = require('path'),

  log = require('fedtools-logs'),
  config = require('fedtools-config'),

  common = require('../common'),

  EnvtoolsBase = require('./base'),
  EnvtoolsVersion;

// -- C O N S T R U C T O R

EnvtoolsVersion = function () {
  EnvtoolsBase.call(this);
};

// -- I N H E R I T A N C E

util.inherits(EnvtoolsVersion, EnvtoolsBase);
EnvtoolsVersion.prototype.name = 'EnvtoolsVersion';

// -- E X T E N D E D  M E T H O D S

EnvtoolsVersion.prototype._initialize = function () {
  var
    rcInfo,
    canCheck = false,
    needToCheck = false;

  EnvtoolsBase.prototype._initialize.call(this);

  // check for current version
  this.currentVersion = this.packageJson.version;

  // checking if the version was already benn checked recently
  rcInfo = this._getConfiguration();
  if (rcInfo && rcInfo[common.ENVTOOLS.CFG_AUTOCHECK] === common.ON) {
    canCheck = true;
  }
  if (canCheck && rcInfo && rcInfo.expiration) {
    // all the keys are here, let's check the expiration
    if (moment().isAfter(rcInfo.expiration)) {
      // time's out, need to check if there is a new version
      // Spawn a detached process that will update the key 'version'
      // from the .fedtoolsrc file with the following sub-keys:
      // version: {
      //   expiration: Now + 1d
      //   latest: x.y.z
      // }
      // It's non-blocking so the next time envtools run, just
      // checking the .fedtoolsrc file is enough.
      needToCheck = true;
    }
  } else {
    needToCheck = canCheck;
  }

  if (needToCheck) {
    require('child_process')
      .spawn(process.execPath, [path.join(__dirname, '..', '..', 'bin', 'check.js')], {
        detached: true,
        stdio: 'ignore'
      }).unref();
  }
};

// -- P R I V A T E  M E T H O D S
EnvtoolsVersion.prototype._getConfiguration = function () {
  return config.getKey('envtoolsversion');
};

// -- P U B L I C  M E T H O D S

EnvtoolsVersion.prototype.setAutoCheck = function (flag) {
  var
    o = {};
  o[common.ENVTOOLS.CFG_AUTOCHECK] = flag;
  config.setKey('envtoolsversion', _.extend(this._getConfiguration(), o), true, true);
};

EnvtoolsVersion.prototype.getAutoCheck = function () {
  var
    cfg = this._getConfiguration();

  if (cfg) {
    return (cfg[common.ENVTOOLS.CFG_AUTOCHECK]) ? cfg[common.ENVTOOLS.CFG_AUTOCHECK] : common.OFF;
  } else {
    return common.OFF;
  }
};

/**
 * This method will read the .fedtoolrc configuration file.
 * It will then display the 'update available' box if the one of
 * the following is true:
 * 1) cfg.alreadyDisplayed is falsy and cfg.latest is truthy
 * 2) force is true and cfg.latest is truthy
 * If it does, it will also update the configuration file to mark
 * that the message has been displayed to the user. (no need to
 * display it again. This flag will be removed automatically after
 * one day).
 *
 * @method printUpgradeIfAny
 * @param  {Boolean} force If true, ignore the 'alreadyDisplayed' key
 */
EnvtoolsVersion.prototype.printUpgradeIfAny = function (force) {
  var
    self = this,
    msg = [],
    boxColor,
    lightGrey = 245,
    rcInfo = this._getConfiguration() || {},
    LATEST_IS_INSTALLED = 'You are up-to-date!',
    NO_DATA_AVAILABLE = 'There is no data available at this time.\nPlease check again later...',
    AUTOCHECK_DISABLED = 'Automatically check for update is disabled.\nYou can enable this option by typing ' +
    log.strToColor(lightGrey, 'envtools config') +
    '\nand following the instructions at the prompt.';

  function printCustomMessage(msgs, boxColor) {
    log.echo();
    log.printMessagesInBox(msgs, (boxColor) ? boxColor : 'yellow');
    log.echo();
    return true;
  }

  if (force && !rcInfo) {
    return printCustomMessage([NO_DATA_AVAILABLE]);
  }

  if (force && rcInfo &&
    rcInfo[common.ENVTOOLS.CFG_AUTOCHECK] !== common.ON) {
    return printCustomMessage([AUTOCHECK_DISABLED]);
  }

  if (rcInfo && rcInfo.latest) {
    if (require('semver').gt(rcInfo.latest, self.currentVersion)) {
      boxColor = 'cyan';
      msg.push('');
      msg.push('A new version of Envtools has been published!');
      msg.push('Envtools ' +
        log.strToColor('green', rcInfo.latest) +
        ' is now available - you have ' +
        log.strToColor(lightGrey, self.currentVersion));
      msg.push('Type ' +
        log.strToColor(lightGrey, 'npm install -g envtools') +
        ' to upgrade.');
      msg.push('');
    } else if (force) {
      boxColor = 'green';
      msg.push('');
      msg.push(LATEST_IS_INSTALLED + ' (' + self.currentVersion + ')');
      msg.push('');
    }
  } else if (force) {
    return printCustomMessage([NO_DATA_AVAILABLE]);
  }

  if (msg.length && (!rcInfo.alreadyDisplayed || force)) {
    // need to mark version as displayed so that it won't
    // be shown to the user again (until the expiration date)
    config.setKey('envtoolsversion', _.extend(rcInfo, {
      alreadyDisplayed: true
    }), true, true);

    return printCustomMessage(msg, boxColor);
  }
};

/**
 * This method is supposed to be called explicitely by the user (for
 * example, envtools -v). In that case, we assume that we can present
 * the current version, but also the 'update available' message.
 *
 * @method printCurrentVersion
 */
EnvtoolsVersion.prototype.printCurrentVersion = function (boring, done) {
  if (!this.printUpgradeIfAny()) {
    log.echo();
    log.printMessagesInBox([
      '',
      this.i18n.t('version.installed') + log.strToColor('green', this.currentVersion),
      ''
    ]);
    log.echo();
  }
  done();
};

// -- E X P O R T S
module.exports = (function () {
  return EnvtoolsVersion._instance || new EnvtoolsVersion();
})();
<|endoftext|>


<commit_before>var CloudCmd, Util, DOM;
(function(CloudCmd, Util, DOM){
    'use strict';

    CloudCmd.Help = HelpProto;

    function HelpProto() {
        var Images      = DOM.Images,
            Help        = this;

        function init() {
            Images.showLoad({
                top: true
            });
            Help.show();
        }

        this.show                       = function() {
            CloudCmd
                .Markdown
                .show('/HELP.md', {
                    topLoad : true,
                    relative: true
                });
        };

        this.hide                       = function() {
            CloudCmd.View.hide();
        };

        init();
    }

})(CloudCmd, Util, DOM);
<commit_msg>chore(help) add "\n"<commit_after>var CloudCmd, Util, DOM;

(function(CloudCmd, Util, DOM) {
    'use strict';

    CloudCmd.Help = HelpProto;

    function HelpProto() {
        var Images      = DOM.Images,
            Help        = this;

        function init() {
            Images.showLoad({
                top: true
            });
            Help.show();
        }

        this.show                       = function() {
            CloudCmd
                .Markdown
                .show('/HELP.md', {
                    topLoad : true,
                    relative: true
                });
        };

        this.hide                       = function() {
            CloudCmd.View.hide();
        };

        init();
    }

})(CloudCmd, Util, DOM);
<|endoftext|>


<commit_before>/**
 * The module instance cache.
 *
 * @class Cache
 */

// require deps
var fs = require('fs-extra');
var watch = require("fwatcher");
var Cache = require('./cache');
var Module = require('./module');

var composition_cache = Cache('compositions');

/**
 * Create a module instance from a composition file.
 *
 * @public
 * @param {string} The module instance name.
 * @param {string} The role name.
 * @param {function} The callback function.
 */
module.exports = function (name, role, callback) {

    var module_instance = engine.instances.get(name, role);

    // check if object is already in cache
    if (module_instance) {
        return callback(null, module_instance);
    }

    // handle access denied
    if (module_instance === 0) {
        var error = new Error('access denied.');
        console.error(error);
        return callback(error);
    }

    // create path to composition file
    var path =  engine.paths.app_composition + name + '.json';

    // read the composition json
    fs.readJson(path, function (err, composition) {

        // handle error and check role access
        if (err || !engine.roleAccess(composition, role)) {
            err = err || new Error('access denied.');
            console.error('lib/comp.js#44', err.toString());
            return callback(err);
        }

        // watch file
        if (module_instance !== null) {
            watch(path, function (err) {
                if (err) {
                    return console.error(err);
                }

                // remove cached data on file change, to force reload
                console.log('COMPOSITION CHANGE:', name);
                // set cached instance to null
                engine.instances.set(name, null, role);
            });
        }

        // check if composition has a module
        if (!composition.module) {

            err = new Error('No module info in composition.');
            console.error('lib/comp.js#65', err.toString());
            return callback(err);
        }

        // set composition name in custom modules
        if (typeof composition.module === 'object' && !composition.module.name) {
            composition.module.name = composition.name;
        }

        // read package info
        getModulePackage(composition.module, function (err, modulePackage) {

            if (err || !modulePackage) {
                err = err || new Error('No package found for module: ' + composition.module);
                console.error('lib/comp.js#73', err.toString());
                return callback(err);
            }

            // add fingerprint to module instance components
            engine.file.prepareComponents({components: composition.client || {}}, function (err, components) {

                    if (err) {
                        console.error('lib/comp.js#90', err.toString());
                        return callback(err);
                    }

                    // get the updated components
                    components = components.components;

                    // merge module components to module instnace
                    if (modulePackage.components) {

                        for (var type in modulePackage.components) {

                            // ensure component type array
                            components[type] = components[type] || [];

                            // push the module components to the module instance components
                            for (var i = 0; i < modulePackage.components[type].length; ++i) {
                                components[type].push(modulePackage.components[type][i]);
                            }
                        }
                    }

                    // update composition client
                    composition.client = components;

                    // indeicate to require the server side module
                    if (modulePackage.main) {
                        composition._server = modulePackage._base + modulePackage.main;
                    }

                    // default module package flow configuration
                    modulePackage.flow = modulePackage.flow || [];
                    modulePackage.clientFlow = modulePackage.clientFlow || [];

                    // create the server flow
                    composition.flow = composition.flow || [];
                    composition.flow = composition.flow.concat(modulePackage.flow);

                    // create the client flow
                    composition.client.flow = composition.client.flow || [];
                    composition.client.flow = composition.client.flow.concat(modulePackage.clientFlow);

                    // create a new module instance
                    module_instance = Module(composition);

                    // handle factory error
                    if (module_instance instanceof Error) {
                        console.error('lib/comp.js#122', module_instance.toString());
                        return callback(module_instance);
                    }

                    // save module instance in cache
                    engine.instances.set(name, module_instance);

                    // save the module instance always under the configured name
                    if (composition.name !== name) {
                        engine.instances.set(composition.name, module_instance);
                    }

                    // return data
                    callback(null, module_instance);
                }
            );
        });
    });
};
<commit_msg>use utils role check to check access for cached instances<commit_after>/**
 * The module instance cache.
 *
 * @class Cache
 */

// require deps
var fs = require('fs-extra');
var watch = require("fwatcher");
var Cache = require('./cache');
var Module = require('./module');
var utils = require('./client/utils');

var composition_cache = Cache('compositions');

/**
 * Create a module instance from a composition file.
 *
 * @public
 * @param {string} The module instance name.
 * @param {string} The role name.
 * @param {function} The callback function.
 */
module.exports = function (name, role, callback) {

    var module_instance = engine.instances[name];

    // check if object is already in cache
    if (module_instance) {

        // check role access
        if (!utils.roleAccess(module_instance, role)) {
            var error = new Error('access denied.');
            console.error(error);
            return callback(error);
        }

        return callback(null, module_instance);
    }
    // create path to composition file
    var path =  engine.paths.app_composition + name + '.json';

    // read the composition json
    fs.readJson(path, function (err, composition) {

        // handle error and check role access
        if (err || !utils.roleAccess(composition, role)) {
            err = err || new Error('access denied.');
            console.error('lib/comp.js#44', err.toString());
            return callback(err);
        }

        // watch file
        if (module_instance !== null) {
            watch(path, function (err) {
                if (err) {
                    return console.error(err);
                }

                // remove cached data on file change, to force reload
                console.log('COMPOSITION CHANGE:', name);
                // set cached instance to null
                engine.instances.set(name, null, role);
            });
        }

        // check if composition has a module
        if (!composition.module) {

            err = new Error('No module info in composition.');
            console.error('lib/comp.js#65', err.toString());
            return callback(err);
        }

        // set composition name in custom modules
        if (typeof composition.module === 'object' && !composition.module.name) {
            composition.module.name = composition.name;
        }

        // read package info
        getModulePackage(composition.module, function (err, modulePackage) {

            if (err || !modulePackage) {
                err = err || new Error('No package found for module: ' + composition.module);
                console.error('lib/comp.js#73', err.toString());
                return callback(err);
            }

            // add fingerprint to module instance components
            engine.file.prepareComponents({components: composition.client || {}}, function (err, components) {

                    if (err) {
                        console.error('lib/comp.js#90', err.toString());
                        return callback(err);
                    }

                    // get the updated components
                    components = components.components;

                    // merge module components to module instnace
                    if (modulePackage.components) {

                        for (var type in modulePackage.components) {

                            // ensure component type array
                            components[type] = components[type] || [];

                            // push the module components to the module instance components
                            for (var i = 0; i < modulePackage.components[type].length; ++i) {
                                components[type].push(modulePackage.components[type][i]);
                            }
                        }
                    }

                    // update composition client
                    composition.client = components;

                    // indeicate to require the server side module
                    if (modulePackage.main) {
                        composition._server = modulePackage._base + modulePackage.main;
                    }

                    // default module package flow configuration
                    modulePackage.flow = modulePackage.flow || [];
                    modulePackage.clientFlow = modulePackage.clientFlow || [];

                    // create the server flow
                    composition.flow = composition.flow || [];
                    composition.flow = composition.flow.concat(modulePackage.flow);

                    // create the client flow
                    composition.client.flow = composition.client.flow || [];
                    composition.client.flow = composition.client.flow.concat(modulePackage.clientFlow);

                    // create a new module instance
                    module_instance = Module(composition);

                    // handle factory error
                    if (module_instance instanceof Error) {
                        console.error('lib/comp.js#122', module_instance.toString());
                        return callback(module_instance);
                    }

                    // save module instance in cache
                    engine.instances.set(name, module_instance);

                    // save the module instance always under the configured name
                    if (composition.name !== name) {
                        engine.instances.set(composition.name, module_instance);
                    }

                    // return data
                    callback(null, module_instance);
                }
            );
        });
    });
};
<|endoftext|>


<commit_before>~function() {

function descend(node, out) {
  if (node.nodeType == Node.ELEMENT_NODE) {
    out.push(node);

    for (var i = 0; i < node.attributes.length; ++i)
      out.attribute(node.attributes[i]);

    var child = node.firstChild;
    while (child) {
      descend(child, out);
      child = child.nextSibling;
    }

    out.pop();
  } else if (node.nodeType == Node.COMMENT_NODE) {
    out.comment(node.textContent);
  } else if (node.nodeType == Node.TEXT_NODE) {
    out.text(node.textContent);
  }
}

function Recorder() {
  this.log = [];
}

Recorder.prototype.base = function(url) {
  this.log.push({ 't': 'b', 'v': url });
}

Recorder.prototype.attribute = function(attribute) {
  this.log.push({ 't': 'a', 'n': attribute.name, 'v': attribute.value });
}

Recorder.prototype.push = function(node) {
  this.log.push({ 't': 'n', 'n': node.nodeName });
}

Recorder.prototype.pop = function() {
  this.log.push({ 't': '/' });
}

Recorder.prototype.text = function(text) {
  this.log.push({ 't': 't', 'v': text })
}

Recorder.prototype.comment = function(comment) {
  this.log.push({ 't': 'c', 'v': comment })
}

Recorder.prototype.save = function() {
  var blob = new Blob([JSON.stringify(this.log)], { type: 'application/octet-binary' });
  var blobURL = window.webkitURL.createObjectURL(blob);
  var link = document.createElement('a');
  link.href = blobURL;
  link.download = encodeURIComponent(window.location).replace(/\./g, '-').replace(/\%[0-9A-F]{2}/g, '-') + '.ds.json';
  link.click();
}

var recorder = new Recorder();

recorder.base(String(window.location));
descend(document.documentElement, recorder);

recorder.save();

}();
<commit_msg>Prevent script from being dumped when saving.<commit_after>~function() {

function descend(node, out) {
  if (node.nodeType == Node.ELEMENT_NODE) {
    if (node.nodeName == 'SCRIPT')
      return;
    out.push(node);

    for (var i = 0; i < node.attributes.length; ++i)
      out.attribute(node.attributes[i]);

    var child = node.firstChild;
    while (child) {
      descend(child, out);
      child = child.nextSibling;
    }

    out.pop();
  } else if (node.nodeType == Node.COMMENT_NODE) {
    out.comment(node.textContent);
  } else if (node.nodeType == Node.TEXT_NODE) {
    out.text(node.textContent);
  }
}

function Recorder() {
  this.log = [];
}

Recorder.prototype.base = function(url) {
  this.log.push({ 't': 'b', 'v': url });
}

Recorder.prototype.attribute = function(attribute) {
  this.log.push({ 't': 'a', 'n': attribute.name, 'v': attribute.value });
}

Recorder.prototype.push = function(node) {
  this.log.push({ 't': 'n', 'n': node.nodeName });
}

Recorder.prototype.pop = function() {
  this.log.push({ 't': '/' });
}

Recorder.prototype.text = function(text) {
  this.log.push({ 't': 't', 'v': text })
}

Recorder.prototype.comment = function(comment) {
  this.log.push({ 't': 'c', 'v': comment })
}

Recorder.prototype.save = function() {
  var blob = new Blob([JSON.stringify(this.log)], { type: 'application/octet-binary' });
  var blobURL = window.webkitURL.createObjectURL(blob);
  var link = document.createElement('a');
  link.href = blobURL;
  link.download = encodeURIComponent(window.location).replace(/\./g, '-').replace(/\%[0-9A-F]{2}/g, '-') + '.ds.json';
  link.click();
}

var recorder = new Recorder();

recorder.base(String(window.location));
descend(document.documentElement, recorder);

recorder.save();

}();
<|endoftext|>


<commit_before>'use babel'

/* @flow */

import {CompositeDisposable, Emitter} from 'atom'
import {Connection} from './connection'
import type {Disposable} from 'atom'

export class Connections {
  queue: Promise;
  emitter: Emitter;
  connections: Map<string, Connection>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.queue = Promise.resolve()
    this.emitter = new Emitter()
    this.connections = new Map()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }
  add(path: string) {
    this.queue = this.queue.then(async () => {
      const connection = await Connection.create(path)
      if (connection) {
        this.connections.set(path, connection)
        this.emitter.emit('did-add-connection', {path, connection})
        connection.onDidReceiveAnyMessage(({type, message}) => {
          this.emitter.emit(`did-receive-message:${type}`, message)
        })
      }
    })
  }
  remove(path: string) {
    this.queue = this.queue.then(() => {
      this.connections.delete(path)
    })
  }
  getByFilePath(path: string): ?Connection {
    for (const connection of this.connections.values()) {
      if (connection.matchesFile(path)) {
        return connection
      }
    }
    return null
  }
  onDidReceiveMessage(type: string, callback: ((message: Object) => void)): Disposable {
    return this.emitter.on(`did-receive-message:${type}`, callback)
  }
  onDidAddConnection(callback: ((parameters: {path: string, connection: Connection}) => void)): Disposable {
    return this.emitter.on('did-add-connection', callback)
  }
  dispose() {
    this.connections.clear()
    this.subscriptions.dispose()
  }
}
<commit_msg>:art: Provide connection with message in connections<commit_after>'use babel'

/* @flow */

import {CompositeDisposable, Emitter} from 'atom'
import {Connection} from './connection'
import type {Disposable} from 'atom'

export class Connections {
  queue: Promise;
  emitter: Emitter;
  connections: Map<string, Connection>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.queue = Promise.resolve()
    this.emitter = new Emitter()
    this.connections = new Map()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }
  add(path: string) {
    this.queue = this.queue.then(async () => {
      const connection = await Connection.create(path)
      if (connection) {
        this.connections.set(path, connection)
        this.emitter.emit('did-add-connection', {path, connection})
        connection.onDidReceiveAnyMessage(({type, message}) => {
          this.emitter.emit(`did-receive-message:${type}`, {message, connection})
        })
      }
    })
  }
  remove(path: string) {
    this.queue = this.queue.then(() => {
      this.connections.delete(path)
    })
  }
  getByFilePath(path: string): ?Connection {
    for (const connection of this.connections.values()) {
      if (connection.matchesFile(path)) {
        return connection
      }
    }
    return null
  }
  onDidReceiveMessage(type: string, callback: ((param: {message: Object, connection: Connection}) => void)): Disposable {
    return this.emitter.on(`did-receive-message:${type}`, callback)
  }
  onDidAddConnection(callback: ((parameters: {path: string, connection: Connection}) => void)): Disposable {
    return this.emitter.on('did-add-connection', callback)
  }
  dispose() {
    this.connections.clear()
    this.subscriptions.dispose()
  }
}
<|endoftext|>


<commit_before>/*
 * These are routines used by our testing code.
 *
 * jQuery is not necesarily present. Don't rely on it
 * for routine operations.
 */

function ph_init ()
{
}

function ph_select(sel)
{
    if (window.$)
        return $(sel);

    if (sel.indexOf(':') != -1 ||
        sel.indexOf('(') != -1 ||
        sel.indexOf(')') != -1 ||
        sel.indexOf('"') != -1 ||
        sel.indexOf("'") != -1)
        throw "cannot use selector without jQuery: " + sel;

    if (sel.indexOf('#') === 0) {
        var el = document.getElementById(sel.substring(1));
        if (!el)
            return [ ];
        return [ el ];
    }

    var els;
    if (sel.indexOf('.'))
        els = document.getElementsByClassName(sel.substring(1));
    else
        els = document.getElementsByTagName(sel);
    return els;
}

function ph_only(els)
{
    if (els.length === 0)
        throw sel + " not found";
    if (els.length > 1)
        throw sel + " is ambigous";
    return els[0];
}

function ph_find (sel)
{
    var els = ph_select(sel);
    return ph_only(els);
}

function ph_val (sel)
{
    var el = ph_find(sel);
    if (el.value === undefined)
        throw sel + " does not have a value";
    return el.value;
}

function ph_set_val (sel, val)
{
    var el = ph_find(sel);
    if (el.value === undefined)
        throw sel + " does not have a value";
    el.value = val;
    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_has_val (sel, val)
{
    return ph_val(sel) == val;
}

function ph_text (sel)
{
    var el = ph_find(sel);
    if (el.textContent === undefined)
        throw sel + " can not have text";
    return el.textContent;
}

function ph_attr (sel, attr)
{
    return ph_find(sel).getAttribute(attr);
}

function ph_set_attr (sel, attr, val)
{
    var el = ph_find(sel);
    if (val === null || val === undefined)
        el.removeAttribute(attr);
    else
        el.setAttribute(attr, val);

    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_has_attr (sel, attr, val)
{
    return ph_attr(sel, attr) == val;
}

function ph_click (sel)
{
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
            "click",
            true /* bubble */, true /* cancelable */,
            window, null,
            0, 0, 0, 0, /* coordinates */
            false, false, false, false, /* modifier keys */
            0 /*left*/, null);
    ph_find(sel).dispatchEvent(ev);
}

function ph_set_checked (sel, val)
{
    var el = ph_find(sel);
    if (el.checked === undefined)
        throw sel + " is not checkable";
    el.checked = val;

    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_is_visible (sel)
{
    if (window.$) {
        var $sel = ph_select(sel);
        ph_only($sel);
        return $sel.is(':visible') && !$sel.is(':animated');
    } else {
        var el = ph_find(sel);
        return (el.offsetParent !== null);
    }
}

function ph_is_present(sel)
{
    var els = ph_select(sel);
    return els.length > 0;
}

function ph_in_text (sel, text)
{
    return ph_text(sel).indexOf(text) != -1;
}

function ph_text_is (sel, text)
{
    return ph_text(sel) == text;
}

function ph_go (hash)
{
    window.location.hash = hash;
}

function ph_focus(sel)
{
    ph_find(sel).focus();
}

function ph_dbus_ready (client_address, client_options)
{
    client_options.payload = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var result = client && client.state == "ready";
    client.release();
    return result;
}

function ph_dbus_prop (client_address, client_options, iface, prop, text)
{
    // check whether there is any object that has the given text as
    // the value of the given property

    var result = false;
    client_options.protocol = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var objs = client.getObjectsFrom("/");
    for (var i = 0; i < objs.length; i++) {
        var obj_iface = objs[i].lookup(iface);
        if (obj_iface && obj_iface[prop] && obj_iface[prop] == text) {
            result = objs[i].objectPath;
            break;
        }
    }
    client.release()
    return result;
}

function ph_dbus_object_prop (client_address, client_options, path, iface, prop, text)
{
    // check whether the given property has the given value

    client_options.protocol = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var proxy = client.lookup(path, iface);
    var result = proxy && proxy[prop] == text;
    client.release()
    return result;
}
<commit_msg>test: Fix ph_only to be able to report errors<commit_after>/*
 * These are routines used by our testing code.
 *
 * jQuery is not necesarily present. Don't rely on it
 * for routine operations.
 */

function ph_init ()
{
}

function ph_select(sel)
{
    if (window.$)
        return $(sel);

    if (sel.indexOf(':') != -1 ||
        sel.indexOf('(') != -1 ||
        sel.indexOf(')') != -1 ||
        sel.indexOf('"') != -1 ||
        sel.indexOf("'") != -1)
        throw "cannot use selector without jQuery: " + sel;

    if (sel.indexOf('#') === 0) {
        var el = document.getElementById(sel.substring(1));
        if (!el)
            return [ ];
        return [ el ];
    }

    var els;
    if (sel.indexOf('.'))
        els = document.getElementsByClassName(sel.substring(1));
    else
        els = document.getElementsByTagName(sel);
    return els;
}

function ph_only(els, sel)
{
    if (els.length === 0)
        throw sel + " not found";
    if (els.length > 1)
        throw sel + " is ambigous";
    return els[0];
}

function ph_find (sel)
{
    var els = ph_select(sel);
    return ph_only(els, sel);
}

function ph_val (sel)
{
    var el = ph_find(sel);
    if (el.value === undefined)
        throw sel + " does not have a value";
    return el.value;
}

function ph_set_val (sel, val)
{
    var el = ph_find(sel);
    if (el.value === undefined)
        throw sel + " does not have a value";
    el.value = val;
    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_has_val (sel, val)
{
    return ph_val(sel) == val;
}

function ph_text (sel)
{
    var el = ph_find(sel);
    if (el.textContent === undefined)
        throw sel + " can not have text";
    return el.textContent;
}

function ph_attr (sel, attr)
{
    return ph_find(sel).getAttribute(attr);
}

function ph_set_attr (sel, attr, val)
{
    var el = ph_find(sel);
    if (val === null || val === undefined)
        el.removeAttribute(attr);
    else
        el.setAttribute(attr, val);

    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_has_attr (sel, attr, val)
{
    return ph_attr(sel, attr) == val;
}

function ph_click (sel)
{
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
            "click",
            true /* bubble */, true /* cancelable */,
            window, null,
            0, 0, 0, 0, /* coordinates */
            false, false, false, false, /* modifier keys */
            0 /*left*/, null);
    ph_find(sel).dispatchEvent(ev);
}

function ph_set_checked (sel, val)
{
    var el = ph_find(sel);
    if (el.checked === undefined)
        throw sel + " is not checkable";
    el.checked = val;

    var ev = document.createEvent("Event");
    ev.initEvent("change", true, false);
    el.dispatchEvent(ev);
}

function ph_is_visible (sel)
{
    if (window.$) {
        var $sel = ph_select(sel);
        ph_only($sel, sel);
        return $sel.is(':visible') && !$sel.is(':animated');
    } else {
        var el = ph_find(sel);
        return (el.offsetParent !== null);
    }
}

function ph_is_present(sel)
{
    var els = ph_select(sel);
    return els.length > 0;
}

function ph_in_text (sel, text)
{
    return ph_text(sel).indexOf(text) != -1;
}

function ph_text_is (sel, text)
{
    return ph_text(sel) == text;
}

function ph_go (hash)
{
    window.location.hash = hash;
}

function ph_focus(sel)
{
    ph_find(sel).focus();
}

function ph_dbus_ready (client_address, client_options)
{
    client_options.payload = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var result = client && client.state == "ready";
    client.release();
    return result;
}

function ph_dbus_prop (client_address, client_options, iface, prop, text)
{
    // check whether there is any object that has the given text as
    // the value of the given property

    var result = false;
    client_options.protocol = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var objs = client.getObjectsFrom("/");
    for (var i = 0; i < objs.length; i++) {
        var obj_iface = objs[i].lookup(iface);
        if (obj_iface && obj_iface[prop] && obj_iface[prop] == text) {
            result = objs[i].objectPath;
            break;
        }
    }
    client.release()
    return result;
}

function ph_dbus_object_prop (client_address, client_options, path, iface, prop, text)
{
    // check whether the given property has the given value

    client_options.protocol = "dbus-json1";
    var client = cockpit.dbus(client_address, client_options);
    var proxy = client.lookup(path, iface);
    var result = proxy && proxy[prop] == text;
    client.release()
    return result;
}
<|endoftext|>


<commit_before>var helper = require("./common.js");
helper.setObject("policy");

var Resource = helper.resource();

helper.nock(helper.test_shop)
.get('/admin/policies.json')
.reply(200, helper.load("all"), {
  server: 'nginx',
  status: '200 OK'
});

describe('Policy', function() {
  var site = helper.endpoint;
  var resource = new Resource(site);

  it('should get all policies', function(done) {
    resource.all(function(err, res){
      res.should.not.be.empty;
      res[0].should.have.property('title');
      res[0].title.should.equal('Refund Policy');
      done();
    });
  });
});
<commit_msg>add test to check the response need to be an Array<commit_after>var helper = require("./common.js");
helper.setObject("policy");

var Resource = helper.resource();

helper.nock(helper.test_shop)
.get('/admin/policies.json')
.reply(200, helper.load("all"), {
  server: 'nginx',
  status: '200 OK'
});

describe('Policy', function() {
  var site = helper.endpoint;
  var resource = new Resource(site);

  it('should get all policies', function(done) {
    resource.all(function(err, res){
      res.should.not.be.empty;
      res.should.be.an.Array();
      res[0].should.have.property('title');
      res[0].title.should.equal('Refund Policy');
      done();
    });
  });
});
<|endoftext|>