<commit_before>import React, {Component, PropTypes} from 'react';

import MonthPicker from 'src/MonthPicker';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/MonthPicker.json';

import 'sass/containers/app/modules/date/DatePickerExamples.scss';

export default class MonthPickerExamples extends Component {

    constructor(props) {
        super(props);
    }

    onChangeHandle(value) {
        console.log(value)
    }

    render() {

        return (

Month Picker

                    Month Picker is used to select a single date for an input.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="Basic"/>

                                    Month Picker using the value property to set
                                    initial date.

                                <MonthPicker name="date"
                                             label={'date'}
                                             dateFormat={'YYYY/MM'}
                                             autoClose={false}
                                             onChange={this.onChangeHandle}/>

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
};
<commit_msg>update MonthPicker examples<commit_after>import React, {Component, PropTypes} from 'react';

import MonthPicker from 'src/MonthPicker';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/MonthPicker.json';

export default class MonthPickerExamples extends Component {

    constructor(props) {
        super(props);
    }

    onChangeHandle(value) {
        console.log(value);
    }

    render() {

        return (

Month Picker

                    Month Picker is used to select a single date for an input.

Examples

                <Widget>

                    <WidgetHeader className="example-header" title="Basic"/>

                                    Month Picker using the value property to set
                                    initial date.

                                <MonthPicker name="date"
                                             label={'date'}
                                             dateFormat={'YYYY/MM'}
                                             autoClose={false}
                                             onChange={this.onChangeHandle}/>

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
};
<|endoftext|>


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

/**
 * Get all repos in phetsims that are not archived, disabled, or forks. This probably won't work unless you have
 * admin privileges to read all repos.
 *
 * This is not intended to be run directly. It's used by areAllReposInFile.js.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

const buildLocal = require( '../../perennial/js/common/buildLocal' );
const https = require( 'https' );

const getSomeRepos = async pageNumber => {
  return new Promise( resolve => {

    const requestOptions = {
      host: 'api.github.com',
      path: `/orgs/phetsims/repos?per_page=100&page=${pageNumber}`,
      method: 'GET',
      auth: `${buildLocal.developerGithubUsername}:${buildLocal.developerGithubAccessToken}`,
      headers: {
        'User-Agent': 'PhET'
      }
    };

    const request = https.request( requestOptions, res => {

      let data = '';
      res.on( 'data', d => {
        data += d.toString();
      } );

      res.on( 'end', () => {
        const repoData = JSON.parse( data.toString() );
        resolve( repoData.filter( x => {
          return !x.archived && !x.disabled && !x.fork; // no repos that are archived, disabled, or actually just forks
        } ).map( x => x.name ) );
      } );
    } );

    request.on( 'error', e => { throw e; } );
    request.end();
  } );
};

/**
 * @returns {Promise<string[]>}
 */
module.exports = async () => {
  let repos = [];

  for ( let i = 1; i < 5; i++ ) {
    repos = repos.concat( await getSomeRepos( i ) );
  }
  return repos.sort();
};
<commit_msg>move jsdoc dot for parameter types to bad-text, update regex and fix errors, https://github.com/phetsims/chipper/issues/1003<commit_after>// Copyright 2021, University of Colorado Boulder

/**
 * Get all repos in phetsims that are not archived, disabled, or forks. This probably won't work unless you have
 * admin privileges to read all repos.
 *
 * This is not intended to be run directly. It's used by areAllReposInFile.js.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

const buildLocal = require( '../../perennial/js/common/buildLocal' );
const https = require( 'https' );

const getSomeRepos = async pageNumber => {
  return new Promise( resolve => {

    const requestOptions = {
      host: 'api.github.com',
      path: `/orgs/phetsims/repos?per_page=100&page=${pageNumber}`,
      method: 'GET',
      auth: `${buildLocal.developerGithubUsername}:${buildLocal.developerGithubAccessToken}`,
      headers: {
        'User-Agent': 'PhET'
      }
    };

    const request = https.request( requestOptions, res => {

      let data = '';
      res.on( 'data', d => {
        data += d.toString();
      } );

      res.on( 'end', () => {
        const repoData = JSON.parse( data.toString() );
        resolve( repoData.filter( x => {
          return !x.archived && !x.disabled && !x.fork; // no repos that are archived, disabled, or actually just forks
        } ).map( x => x.name ) );
      } );
    } );

    request.on( 'error', e => { throw e; } );
    request.end();
  } );
};

/**
 * @returns {Promise.<string[]>}
 */
module.exports = async () => {
  let repos = [];

  for ( let i = 1; i < 5; i++ ) {
    repos = repos.concat( await getSomeRepos( i ) );
  }
  return repos.sort();
};
<|endoftext|>


<commit_before>function AnswerViewModel(data) {
    var self = this;

    self.id = ko.observable(data.Id);
    self.moodId = ko.observable(data.MoodId);
    self.moodName = ko.observable(data.Mood.Description);
    self.details = ko.observable(data.Details);
    self.time = ko.observable(moment(data.Time).local());
    self.timeString = ko.computed(function () { return self.time().format('LLLL') });

    return self;
}<commit_msg>Need to start from UTC before local conversion makes sense<commit_after>function AnswerViewModel(data) {
    var self = this;

    self.id = ko.observable(data.Id);
    self.moodId = ko.observable(data.MoodId);
    self.moodName = ko.observable(data.Mood.Description);
    self.details = ko.observable(data.Details);
    self.time = ko.observable(moment.utc(data.Time).local());
    self.timeString = ko.computed(function () { return self.time().format('LLLL') });

    return self;
}<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var $ = require('jquery');
var _ = require('underscore');

/**
 *  Video player
 *
 */
module.exports = cdb.core.View.extend({

  className: 'VideoPlayer',

  events: {

  },

  initialize: function() {

    this.video = this.options.video;
    this.model = new cdb.core.Model({
      duration: 0,
      percent: 0,
      seconds: 0
    });

    this.template = cdb.templates.getTemplate('new_dashboard/views/video_player');
    this._initBinds();
    //this._loadScript();
  },

  render: function() {
    this.clearSubViews();
    this.$el.html(
      this.template({})
    );
    //this._initViews();
    return this;
  },

  _initBinds: function() {
    this.model.bind('change:duration', this.render, this);
    this.model.bind('change:percent', this._changeProgress, this);
    this.model.bind('change:seconds', this._checkTooltips, this);
  },

  _loadScript: function() {
    var self = this;
    $.getScript('//f.vimeocdn.com/js/froogaloop2.min.js', function() {
      self._initVideoBinds();
    });
  },

  _initVideoBinds: function() {
    var player = $f(this.video[0]);
    var self = this;

    player.addEvent('ready', function() {
      player.api('getDuration', function(dur) {
        self.model.set('duration', dur);
      });

      player.addEvent('playProgress', function(m) {
        self.model.set(m);
      });
    });
  },

  _removeVideoBinds: function() {
    var player = $f(this.video[0]);
    player.removeEvent('ready');
    player.removeEvent('playProgress');
  },

  clean: function() {
    this._removeVideoBinds();
    this.elder('clean');
  }

});
<commit_msg>Removes old file<commit_after><|endoftext|>


<commit_before>'use strict';

var path = require('path');
var del = require('delete');
var prettify = require('gulp-prettify');
var extname = require('gulp-extname');
var ignore = require('gulp-ignore');

var redirects = require('./plugins/redirects');
var manifest = require('./plugins/manifest');
var utils = require('./support/utils');
var pkg = require('../package');
var assemble = require('../');

/**
 * Create our assemble appplication
 */

var app = assemble();

/**
 * Customize how templates are stored. This changes the
 * key of each template, so it's easier to lookup later
 */

app.option('renameKey', function(fp) {
  return path.basename(fp, path.extname(fp));
});

/**
 * Create a custom view collection
 */

app.create('docs');

/**
 * Load helpers
 */

app.helpers('helpers/*.js');

/**
 * Load some "global" data
 */

app.data({
  site: {
    title: 'Assemble Docs'
  },
  destBase: '_gh_pages/',
  assets: 'assets',
  links: [{
    dest: 'assemble',
    collection: 'docs',
    text: 'Assemble'
  }]
});

/**
 * Middleware
 */

app.preLayout(/\/api\/.*\.md$/, function(view, next) {
  view.layout = 'body';
  next();
});

/**
 * Clean out the current version's built files
 */

app.task('clean', function(cb) {
  var pattern = '../_gh_pages/en/v' + pkg.version;
  del(pattern, {force: true}, cb);
});

/**
 * Build manifest for a specific version.
 * This is in case an old version didn't have a manifest or something.
 * Run with `assemble manifest --version 0.6.0`
 */

app.task('manifest', function(cb) {
  // get the version from argv.orig (because of the dots in versions)
  var version = app.argv.orig.version;
  if (typeof version === 'undefined' || typeof version === 'boolean') {
    app.emit('error', new Error('--version needs to be specified when running `assemble manifest`'));
    return cb();
  }

  var dir = '../_gh_pages/en/v' + version;
  if (!utils.exists(dir)) {
    app.emit('error', new Error('invalid version [' + version + ']. ' + dir + ' does not exist'));
    return cb();
  }

  return app.src([dir + '/**/*.html'])
    .on('err', console.log)
    .pipe(manifest(app, {
      renamePath: function(fp) {
        return 'en/v' + version + '/' + fp;
      }
    }))
    .pipe(ignore.include('manifest.json'))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return dir;
    }));
});

/**
 * Build up a redirects.json file
 */

app.task('redirects', function() {
  return app.src(['../_gh_pages/en/*/manifest.json'])
    .pipe(redirects(app))
    .pipe(ignore.include('redirects.json'))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return 'data';
    }));
});

/**
 * Re-load templates when triggered by watch
 */

app.task('load', function(cb) {
  app.partials('templates/partials/*.hbs');
  app.layouts('templates/layouts/*.hbs');
  app.docs('src/api/*.md');
  cb();
});

/**
 * Building the assemble docs
 */

app.task('default', ['clean', 'load'], function() {
  return app.toStream('docs')
    .on('err', console.log)
    .pipe(app.renderFile())
    .on('err', console.log)
    .pipe(prettify())
    .pipe(extname())
    .pipe(manifest(app, {
      renamePath: function(fp) {
        return 'en/v' + pkg.version + '/' + fp;
      }
    }))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return '../_gh_pages/en/v' + pkg.version;
    }))
});

/**
 * Watch files for changes
 */

app.task('watch', ['default'], function() {
  app.watch('**/*.{md,hbs}', ['default']);
  console.log('watching docs templates');
});

/**
 * Expose the `app` instance
 */

module.exports = app;
<commit_msg>adding browser-sync task to view files during development adding dev task for building, serving, and watching files during development<commit_after>'use strict';

var path = require('path');
var del = require('delete');
var browserSync = require('browser-sync').create();
var prettify = require('gulp-prettify');
var extname = require('gulp-extname');
var ignore = require('gulp-ignore');

var redirects = require('./plugins/redirects');
var manifest = require('./plugins/manifest');
var utils = require('./support/utils');
var pkg = require('../package');
var assemble = require('../');

/**
 * Create our assemble appplication
 */

var app = assemble();

/**
 * Customize how templates are stored. This changes the
 * key of each template, so it's easier to lookup later
 */

app.option('renameKey', function(fp) {
  return path.basename(fp, path.extname(fp));
});

/**
 * Create a custom view collection
 */

app.create('docs');

/**
 * Load helpers
 */

app.helper('markdown', require('helper-markdown'));
app.helpers('helpers/*.js');

/**
 * Load some "global" data
 */

app.data({
  site: {
    title: 'Assemble Docs'
  },
  destBase: '_gh_pages/',
  assets: 'assets',
  links: [{
    dest: 'assemble',
    collection: 'docs',
    text: 'Assemble'
  }]
});

/**
 * Middleware
 */

app.preLayout(/\/api\/.*\.md$/, function(view, next) {
  view.layout = 'body';
  next();
});

/**
 * Clean out the current version's built files
 */

app.task('clean', function(cb) {
  var pattern = '../_gh_pages/en/v' + pkg.version;
  del(pattern, {force: true}, cb);
});

/**
 * Build manifest for a specific version.
 * This is in case an old version didn't have a manifest or something.
 * Run with `assemble manifest --version 0.6.0`
 */

app.task('manifest', function(cb) {
  // get the version from argv.orig (because of the dots in versions)
  var version = app.argv.orig.version;
  if (typeof version === 'undefined' || typeof version === 'boolean') {
    app.emit('error', new Error('--version needs to be specified when running `assemble manifest`'));
    return cb();
  }

  var dir = '../_gh_pages/en/v' + version;
  if (!utils.exists(dir)) {
    app.emit('error', new Error('invalid version [' + version + ']. ' + dir + ' does not exist'));
    return cb();
  }

  return app.src([dir + '/**/*.html'])
    .on('err', console.log)
    .pipe(manifest(app, {
      renamePath: function(fp) {
        return 'en/v' + version + '/' + fp;
      }
    }))
    .pipe(ignore.include('manifest.json'))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return dir;
    }));
});

/**
 * Build up a redirects.json file
 */

app.task('redirects', function() {
  return app.src(['../_gh_pages/en/*/manifest.json'])
    .pipe(redirects(app))
    .pipe(ignore.include('redirects.json'))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return 'data';
    }));
});

/**
 * Re-load templates when triggered by watch
 */

app.task('load', function(cb) {
  app.partials('templates/partials/*.hbs');
  app.layouts('templates/layouts/*.hbs');
  app.docs('src/api/*.md');
  cb();
});

/**
 * Static server
 */

app.task('serve', function() {
  browserSync.init({
    port: 8080,
    startPath: 'en/v' + pkg.version + '/assemblefile.html',
    server: {
      baseDir: '../_gh_pages'
    }
  });
});

/**
 * Building the assemble docs
 */

app.task('build', ['load'], function() {
  return app.toStream('docs')
    .on('err', console.log)
    .pipe(app.renderFile())
    .on('err', console.log)
    .pipe(prettify())
    .pipe(extname())
    .pipe(manifest(app, {
      renamePath: function(fp) {
        return 'en/v' + pkg.version + '/' + fp;
      }
    }))
    .pipe(app.dest(function(file) {
      file.base = file.dirname;
      return '../_gh_pages/en/v' + pkg.version;
    }))
    .pipe(browserSync.stream());
});

/**
 * Watch files for changes
 */

app.task('watch', function() {
  app.watch('**/*.{md,hbs}', ['build']);
  console.log('watching docs templates');
});

/**
 * Alias for building, serving, and watching docs during development.
 */

app.task('dev', ['default'], app.parallel(['serve', 'watch']));

/**
 * Alias for cleaning and building docs.
 */

app.task('default', ['clean', 'build']);

/**
 * Expose the `app` instance
 */

module.exports = app;
<|endoftext|>


<commit_before>function infix_to_postfix(input) {
  const op_stack = [], expr = [];
  let tc = '';

  const operator = {
    '*': 3, '/': 3,
    '+': 2, '-': 2,
    '(': 1, ')': 1
  };

  const peek = s => s[s.length - 1];

  for (let c of String(input)) {
    if (/[\d.]/.test(c)) {
      tc += c; continue;
    }

    if (tc.length) {
      expr.push(tc); tc = '';
    }

    if (operator[c]) {
      if (c == '(') {
        op_stack.push(c);
      }

      else if (c == ')') {
        while (op_stack.length && peek(op_stack) != '(') {
          expr.push(op_stack.pop());
        }
        op_stack.pop();
      }

      else {
        while (op_stack.length && operator[peek(op_stack)] >= operator[c]) {
          let op = op_stack.pop();
          if (!/[()]/.test(op)) expr.push(op);
        }
        op_stack.push(c);
      }
    }
  }

  if (tc.length) {
    expr.push(tc);
  }

  while (op_stack.length) {
    expr.push(op_stack.pop());
  }

  return expr;
}

function compute(op, a, b) {
  switch (op) {
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    case '/': return a / b;
  }
}

export default function calculate(input) {
  const expr = infix_to_postfix(input), stack = [];
  while (expr.length) {
    let top = expr.shift();
    if (/\d+/.test(top)) stack.push(top);
    else {
      let right = stack.pop();
      let left = stack.pop();
      stack.push(compute(
        top, Number(left), Number(right)
      ));
    }
  }
  return stack[0];
}
<commit_msg>Support % operator<commit_after>/**
 * Base on the Shunting-yard algorithm.
 */

function infix_to_postfix(input) {
  const op_stack = [], expr = [];
  let tc = '';

  const operator = {
    '*': 3, '/': 3, '%': 3,
    '+': 2, '-': 2,
    '(': 1, ')': 1
  };

  const peek = s => s[s.length - 1];

  for (let c of String(input)) {
    if (/[\d.]/.test(c)) {
      tc += c; continue;
    }

    if (tc.length) {
      expr.push(tc); tc = '';
    }

    if (operator[c]) {
      if (c == '(') {
        op_stack.push(c);
      }

      else if (c == ')') {
        while (op_stack.length && peek(op_stack) != '(') {
          expr.push(op_stack.pop());
        }
        op_stack.pop();
      }

      else {
        while (op_stack.length && operator[peek(op_stack)] >= operator[c]) {
          let op = op_stack.pop();
          if (!/[()]/.test(op)) expr.push(op);
        }
        op_stack.push(c);
      }
    }
  }

  if (tc.length) {
    expr.push(tc);
  }

  while (op_stack.length) {
    expr.push(op_stack.pop());
  }

  return expr;
}

function compute(op, a, b) {
  switch (op) {
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    case '/': return a / b;
    case '%': return a % b;
  }
}

export default function calculate(input) {
  const expr = infix_to_postfix(input), stack = [];
  while (expr.length) {
    let top = expr.shift();
    if (/\d+/.test(top)) stack.push(top);
    else {
      let right = stack.pop();
      let left = stack.pop();
      stack.push(compute(
        top, Number(left), Number(right)
      ));
    }
  }
  return stack[0];
}
<|endoftext|>


<commit_before>var WP = {};

/* I wish javascript had foreach for arrays, but alas, I have to provide *
 * it myself. Does what you'd expect.                                    *
 */
WP.foreach = function (a, func) {
	var i;
	for (i = 0; i < a.length; i++) {
		func(a[i]);
	}
};

/* Get the current word in a text input. */
WP.find_word = function (el) {
	var start, end, txt;
	start = el.selectionStart;
	end = el.selectionEnd;
	if (!start || start !== end) { return ""; }
	txt = el.value;
	if (end < txt.length && txt.substr(end, 1) !== " ") { return ""; }
	while (start > 0 && txt.substr(start - 1, 1) !== " ") { start--; }
	return txt.substr(start, end - start);
};

/* Find the (absolute) position of an element. */
WP.findpos = function (el) {
	var x = 0, y = 0;
	while (el) {
		x += el.offsetLeft;
		y += el.offsetTop;
		el = el.offsetParent;
	}
	return {"x": x, "y": y};
};

/* Return prefix character of tagname, if any. */
WP.tag_prefix = function (word) {
	var c = word.substr(0, 1);
	if (c === "-" || c === "~" || c === "!") { return c; }
	return "";
};

/* Return clean tagname, without prefix character. */
WP.tag_clean = function (word) {
	if (WP.tag_prefix(word)) { return word.substr(1); }
	return word;
};

/*************************************/
/* And now, the compatibility hacks. */
/*************************************/

WP.getElementsByClassName = function (el, name) {
	var a, re;
	if (el.getElementsByClassName) {
		return el.getElementsByClassName(name);
	}
	a = [];
	re = new RegExp("\\b" + name + "\\b");
	WP.foreach(document.all, function (el) {
		if (re.test(el.className)) { a.push(el); }
	});
	return a;
};

var JSON;
if (!JSON) { JSON = {}; }
if (!JSON.parse) {
	JSON.parse = function (txt) {
		return eval("(" + txt + ")");
	};
}
<commit_msg>getElementsByClassName-replacement always looked in the entire document.<commit_after>var WP = {};

/* I wish javascript had foreach for arrays, but alas, I have to provide *
 * it myself. Does what you'd expect.                                    *
 */
WP.foreach = function (a, func) {
	var i;
	for (i = 0; i < a.length; i++) {
		func(a[i]);
	}
};

/* Get the current word in a text input. */
WP.find_word = function (el) {
	var start, end, txt;
	start = el.selectionStart;
	end = el.selectionEnd;
	if (!start || start !== end) { return ""; }
	txt = el.value;
	if (end < txt.length && txt.substr(end, 1) !== " ") { return ""; }
	while (start > 0 && txt.substr(start - 1, 1) !== " ") { start--; }
	return txt.substr(start, end - start);
};

/* Find the (absolute) position of an element. */
WP.findpos = function (el) {
	var x = 0, y = 0;
	while (el) {
		x += el.offsetLeft;
		y += el.offsetTop;
		el = el.offsetParent;
	}
	return {"x": x, "y": y};
};

/* Return prefix character of tagname, if any. */
WP.tag_prefix = function (word) {
	var c = word.substr(0, 1);
	if (c === "-" || c === "~" || c === "!") { return c; }
	return "";
};

/* Return clean tagname, without prefix character. */
WP.tag_clean = function (word) {
	if (WP.tag_prefix(word)) { return word.substr(1); }
	return word;
};

/*************************************/
/* And now, the compatibility hacks. */
/*************************************/

WP.getElementsByClassName = function (el, name) {
	var a, re;
	if (el.getElementsByClassName) {
		return el.getElementsByClassName(name);
	}
	a = [];
	re = new RegExp("\\b" + name + "\\b");
	WP.foreach(el.getElementsByTagName("*"), function (el) {
		if (re.test(el.className)) { a.push(el); }
	});
	return a;
};

var JSON;
if (!JSON) { JSON = {}; }
if (!JSON.parse) {
	JSON.parse = function (txt) {
		return eval("(" + txt + ")");
	};
}
<|endoftext|>


<commit_before>import emitter from 'mitt';
import audioPool from './utils/audio-pool';
import feature from './utils/feature';
import { sleep } from './utils/async';

const AudioContext = window.AudioContext || window.webkitAudioContext;

let context;
let source;
let gainNode;
let loopCount;
let duration = 0;
let lastTime = 0;
let startTime;
let audioElement;
let request;
let onCanPlayThrough;
let onPause;
let onPlay;
let pauseTime;
let muted = false;

const FADE_OUT_SECONDS = 2;
const ALMOST_ZERO = 1e-4;

let scheduledTime;
const audio = Object.assign(emitter(), {
  tick() {
    if ((!audioElement && !context) || !startTime) {
      this.progress = 0;
      this.currentTime = 0;
      this.loopProgress = 0;
      this.totalProgress = 0;
      this.looped = false;
      return;
    };
    this.currentTime = audioElement
      ? (pauseTime || (Date.now() - startTime)) / 1000
      : context.currentTime - startTime;
    const time = this.time = this.currentTime % duration;

    const { loopDuration } = this;
    // The position within the track as a multiple of loopDuration:
    this.progress = time > 0
      ? time / loopDuration
      : 0;
    // The position within the individual loop as a value between 0 - 1:
    this.loopProgress = (time % loopDuration) / loopDuration;

    // True when the audio looped, false otherwise:
    this.looped = time < lastTime;

    if (this.looped) {
      // The index of the loop, used when the audio has more than one loops:
      this.loopIndex = Math.floor(this.progress * loopCount);
      this.loopCount++;
    }

    this.totalProgress = this.loopCount * loopCount + this.progress;
    lastTime = time;
  },

  load(param) {
    return new Promise(async (resolve, reject) => {
      if (context) context.close();
      context = new AudioContext();
      gainNode = context.createGain();
      // Reset time, set loop count
      lastTime = 0;
      loopCount = param.loops === undefined
        ? 1
        : param.loops;
      this.loopCount = 0;
      const canPlay = () => {
        this.duration = duration;
        this.loopDuration = duration / loopCount;
        context.suspend();
        resolve(param.src);
      };

      if (param.loopOffset) {
        this.loopOffset = param.loopOffset;
      }

      if (param.progressive) {
        audioElement = feature.isMobile
          ? audioPool.get()
          : new Audio();
        audioElement.addEventListener('ended', () => audio.emit('ended'));
        audioElement.autoplay = true;
        audioElement.src = param.src;
        audioElement.loop = param.loop === undefined ? true : param.loop;
        onCanPlayThrough = () => {
          duration = audioElement.duration;
          canPlay();
          audioElement.removeEventListener('canplaythrough', onCanPlayThrough);
        };
        onPause = () => {
          this.paused = true;
          this.pauseTime = audioElement.currentTime * 1000;
        };
        onPlay = () => {
          startTime = Date.now() - audioElement.currentTime * 1000;
          this.paused = false;
          this.pauseTime = null;
        };
        audioElement.addEventListener('canplaythrough', onCanPlayThrough);
        audioElement.addEventListener('pause', onPause);
        audioElement.addEventListener('play', onPlay);
        source = context.createMediaElementSource(audioElement);
      } else {
        source = context.createBufferSource();
        request = new XMLHttpRequest();
        request.open('GET', param.src, true);
        request.responseType = 'arraybuffer';
        request.onload = () => {
          context.decodeAudioData(
            request.response,
            (response) => {
              // Load the file into the buffer
              source.buffer = response;
              duration = source.buffer.duration;
              source.loop = param.loop === undefined ? true : param.loop;
              source.start(0);
              startTime = context.currentTime;
              canPlay();
            },
            reject
          );
        };
        request.send();
      }
      source.connect(gainNode);
      gainNode.connect(context.destination);
      if (muted) this.mute();
    });
  },

  play() {
    this.paused = false;
    if (context) context.resume();
    if (audioElement) audioElement.play();
  },

  pause() {
    this.paused = true;
    if (context) context.suspend();
    if (audioElement) audioElement.pause();
  },

  toggle() {
    this[this.paused ? 'play' : 'pause']();
  },

  gotoTime(time) {
    audioElement.currentTime = time;
    startTime = Date.now() - time * 1000;
  },

  prevLoop() {
    this.gotoTime(this.time - (1 + this.loopProgress) * this.loopDuration);
  },

  nextLoop() {
    this.gotoTime(this.time + this.loopDuration - this.loopProgress * this.loopDuration);
  },

  reset() {
    audio.fadeOut();
    // Cancel loading of audioElement:
    if (audioElement) {
      audioElement.removeEventListener('canplaythrough', onCanPlayThrough);
      audioElement.removeEventListener('pause', onPause);
      audioElement.removeEventListener('play', onPlay);
      if (feature.isMobile) {
        audioPool.release(audioElement);
      }
      audioElement = null;
      onCanPlayThrough = null;
    }
    if (request) {
      request.abort();
      request.onload = null;
      request = null;
    }
    pauseTime = startTime = null;
  },

  rewind() {
    if (audioElement) {
      audioElement.currentTime = 0;
      gainNode.gain.value = muted ? 0.001 : 1;
    }
  },

  mute() {
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    gainNode.gain.value = 0.001;
  },

  unmute() {
    gainNode.gain.value = 1;
  },

  toggleMute() {
    this[muted ? 'unmute' : 'mute']();
    muted = !muted;
    return muted;
  },

  async fadeOut(fadeDuration = FADE_OUT_SECONDS) {
    if (!context) return;
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    scheduledTime = context.currentTime;
    gainNode.gain.exponentialRampToValueAtTime(
      ALMOST_ZERO,
      scheduledTime + fadeDuration
    );
    return sleep(fadeDuration * 1000);
  },

  async fadeIn(fadeDuration = FADE_OUT_SECONDS) {
    if (!context || muted) return;
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    scheduledTime = context.currentTime;
    gainNode.gain.exponentialRampToValueAtTime(
      1,
      scheduledTime + fadeDuration
    );
    return sleep(fadeDuration * 1000);
  },

  time: 0,
  loopIndex: 0,
});

export default audio;
<commit_msg>fix pausing of audio<commit_after>import emitter from 'mitt';
import audioPool from './utils/audio-pool';
import feature from './utils/feature';
import { sleep } from './utils/async';

const AudioContext = window.AudioContext || window.webkitAudioContext;

let context;
let source;
let gainNode;
let loopCount;
let duration = 0;
let lastTime = 0;
let startTime;
let audioElement;
let request;
let onCanPlayThrough;
let onPause;
let onPlay;
let onSeeked;
let pauseTime;
let muted = false;

const FADE_OUT_SECONDS = 2;
const ALMOST_ZERO = 1e-4;

let scheduledTime;
const audio = Object.assign(emitter(), {
  tick() {
    if ((!audioElement && !context) || !startTime) {
      this.progress = 0;
      this.currentTime = 0;
      this.loopProgress = 0;
      this.totalProgress = 0;
      this.looped = false;
      return;
    }
    this.currentTime = audioElement
      ? (pauseTime || (Date.now() - startTime)) / 1000
      : context.currentTime - startTime;
    const time = this.time = this.currentTime % duration;
    const { loopDuration } = this;
    // The position within the track as a multiple of loopDuration:
    this.progress = time > 0
      ? time / loopDuration
      : 0;
    // The position within the individual loop as a value between 0 - 1:
    this.loopProgress = (time % loopDuration) / loopDuration;

    // True when the audio looped, false otherwise:
    this.looped = time < lastTime;

    if (this.looped) {
      // The index of the loop, used when the audio has more than one loops:
      this.loopIndex = Math.floor(this.progress * loopCount);
      this.loopCount++;
    }

    this.totalProgress = this.loopCount * loopCount + this.progress;
    lastTime = time;
  },

  load(param) {
    return new Promise(async (resolve, reject) => {
      if (context) context.close();
      context = new AudioContext();
      gainNode = context.createGain();
      // Reset time, set loop count
      lastTime = 0;
      loopCount = param.loops === undefined
        ? 1
        : param.loops;
      this.loopCount = 0;
      const canPlay = () => {
        this.duration = duration;
        this.loopDuration = duration / loopCount;
        context.suspend();
        resolve(param.src);
      };

      if (param.loopOffset) {
        this.loopOffset = param.loopOffset;
      }

      if (param.progressive) {
        audioElement = feature.isMobile
          ? audioPool.get()
          : new Audio();
        audioElement.addEventListener('ended', () => audio.emit('ended'));
        audioElement.autoplay = true;
        audioElement.src = param.src;
        audioElement.loop = param.loop === undefined ? true : param.loop;
        const getAudioTime = () => audioElement.currentTime * 1000;
        onCanPlayThrough = () => {
          duration = audioElement.duration;
          canPlay();
          audioElement.removeEventListener('canplaythrough', onCanPlayThrough);
        };
        onPause = () => {
          this.paused = true;
          pauseTime = getAudioTime();
        };
        onPlay = () => {
          startTime = Date.now() - getAudioTime();
          this.paused = false;
          pauseTime = null;
        };
        onSeeked = () => {
          if (pauseTime) {
            pauseTime = getAudioTime();
          }
        };
        audioElement.addEventListener('canplaythrough', onCanPlayThrough);
        audioElement.addEventListener('pause', onPause);
        audioElement.addEventListener('play', onPlay);
        audioElement.addEventListener('seeked', onSeeked);
        source = context.createMediaElementSource(audioElement);
      } else {
        source = context.createBufferSource();
        request = new XMLHttpRequest();
        request.open('GET', param.src, true);
        request.responseType = 'arraybuffer';
        request.onload = () => {
          context.decodeAudioData(
            request.response,
            (response) => {
              // Load the file into the buffer
              source.buffer = response;
              duration = source.buffer.duration;
              source.loop = param.loop === undefined ? true : param.loop;
              source.start(0);
              startTime = context.currentTime;
              canPlay();
            },
            reject
          );
        };
        request.send();
      }
      source.connect(gainNode);
      gainNode.connect(context.destination);
      if (muted) this.mute();
    });
  },

  play() {
    this.paused = false;
    if (context) context.resume();
    if (audioElement) audioElement.play();
  },

  pause() {
    this.paused = true;
    if (context) context.suspend();
    if (audioElement) audioElement.pause();
  },

  toggle() {
    this[this.paused ? 'play' : 'pause']();
  },

  gotoTime(time) {
    audioElement.currentTime = time;
    startTime = Date.now() - time * 1000;
  },

  prevLoop() {
    this.gotoTime(this.time - (1 + this.loopProgress) * this.loopDuration);
  },

  nextLoop() {
    this.gotoTime(this.time + this.loopDuration - this.loopProgress * this.loopDuration);
  },

  reset() {
    audio.fadeOut();
    // Cancel loading of audioElement:
    if (audioElement) {
      audioElement.removeEventListener('canplaythrough', onCanPlayThrough);
      audioElement.removeEventListener('pause', onPause);
      audioElement.removeEventListener('play', onPlay);
      audioElement.removeEventListener('seeked', onSeeked);
      if (feature.isMobile) {
        audioPool.release(audioElement);
      }
      audioElement = null;
      onCanPlayThrough = null;
    }
    if (request) {
      request.abort();
      request.onload = null;
      request = null;
    }
    startTime = null;
  },

  rewind() {
    if (audioElement) {
      audioElement.currentTime = 0;
      gainNode.gain.value = muted ? 0.001 : 1;
    }
  },

  mute() {
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    gainNode.gain.value = 0.001;
  },

  unmute() {
    gainNode.gain.value = 1;
  },

  toggleMute() {
    this[muted ? 'unmute' : 'mute']();
    muted = !muted;
    return muted;
  },

  async fadeOut(fadeDuration = FADE_OUT_SECONDS) {
    if (!context) return;
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    scheduledTime = context.currentTime;
    gainNode.gain.exponentialRampToValueAtTime(
      ALMOST_ZERO,
      scheduledTime + fadeDuration
    );
    return sleep(fadeDuration * 1000);
  },

  async fadeIn(fadeDuration = FADE_OUT_SECONDS) {
    if (!context || muted) return;
    if (scheduledTime) {
      gainNode.gain.cancelScheduledValues(scheduledTime);
    }
    scheduledTime = context.currentTime;
    gainNode.gain.exponentialRampToValueAtTime(
      1,
      scheduledTime + fadeDuration
    );
    return sleep(fadeDuration * 1000);
  },

  time: 0,
  loopIndex: 0,
});

export default audio;
<|endoftext|>


<commit_before>module.exports = function (DBM) {
    const Dashboard = DBM.Dashboard;
    const client = DBM.Bot.bot;
    Dashboard.loadDashboard = function () {
        Dashboard.app.get('/dashboard/@me', Dashboard.checkAuth, function (req, res) {
            res.render('servers', {
                guilds: req.user.guilds.filter(u => (u.permissions & 2146958591) === 2146958591),
                user: req.user,
                config: Dashboard.config,
                client: DBM.Bot.bot,
                theme: Dashboard.theme(),
                req: req
            });
        });

        Dashboard.app.get('/dashboard/@me/servers/:guildID', Dashboard.checkAuth, function (req, res) {
            let serv = client.guilds.get(req.params.guildID);
            if (!serv) return res.redirect(`https://discordapp.com/oauth2/authorize?client_id=${DBM.Bot.bot.user.id}&scope=bot&permissions=2146958591&guild_id=${req.params.guildID}`);
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.dashboardMod == true) {
                    dashboardMods.push(data);
                };
            });
            let section = []
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.dashboardMod == true) {
                    section.push(action.section);
                };
            });
            if (!req.user.log) req.user.log = 'Command Executed';
            res.render('dashboardPanel', {
                client: DBM.Bot.bot,
                server: serv,
                dashboardMods: dashboardMods,
                customHtml: false,
                log: req.user.log,
                config: Dashboard.config,
                commandExecuted: req.user.commandExecuted,
                theme: Dashboard.theme(),
                sections: section,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/@me/servers/:guildID/:action', Dashboard.checkAuth, function (req, res) {
            let serv = client.guilds.get(req.params.guildID);
            if (!serv) return res.redirect(`https://discordapp.com/oauth2/authorize?client_id=${DBM.Bot.bot.user.id}&scope=bot&permissions=2146958591&guild_id=${req.params.guildID}`);
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.dashboardMod == true) dashboardMods.push(data);
            });
            let section = []
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.dashboardMod == true) {
                    section.push(action.section);
                };
            });
            res.render('dashboardPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: req.user.commandExecuted,
                customHtml: data.customHtml,
                action: data,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                server: serv,
                theme: Dashboard.theme(),
                sections: section,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/admin', Dashboard.checkAuthOwner, function (req, res) {
            let config = Dashboard.dashboardConfig();
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.adminMod == true) dashboardMods.push(data);
            });
            if (!req.user.log) req.user.log = 'Command Executed';
            let actions = Dashboard.actions;
            let section = [];
            let extensions = [];
            actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.adminMod == true) {
                    section.push(action.section);
                };
            });

            actions.forEach(action => {
                if (action.extensionMod && action.customHtml) {
                    extensions.push(action);
                };
            });

            res.render('adminPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: req.user.commandExecuted,
                customHtml: false,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                theme: Dashboard.theme(),
                sections: section,
                extensions: extensions,
                app: Dashboard.app,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/admin/:action', Dashboard.checkAuthOwner, function (req, res) {
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let dashboardMods = [];

            Dashboard.actions.forEach(data => {
                if (data.adminMod == true) dashboardMods.push(data);
            });

            let section = [];
            let extensions = [];
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.adminMod == true) {
                    section.push(action.section);
                }
            });

            Dashboard.actions.forEach(action => {
                if (action.extensionMod && action.customHtml) {
                    extensions.push(action);
                };
            });

            let passData = {}
            console.log(data.render(passData))
            res.render('adminPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: false,
                customHtml: true,
                action: data,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                theme: Dashboard.theme(),
                sections: section,
                extensions: extensions,
                app: Dashboard.app,
                req: req,
                render: data.render(passData)
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.post('/api/execute/:action', Dashboard.checkAuthOwner, function (req, res) {
            var next = req.query['next'];
            if (!next) next = false;
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let serv;
            Dashboard.onCommandExecute(req, data);
            if (data.customHtml) {
                if (next == 'true') {
                    data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                    if (data.next) {
                        Dashboard.commandExecuted(req, true);
                        res.redirect('/dashboard/admin');
                    };
                } else {
                    res.redirect(`/dashboard/admin/${data.name}`);
                };
            } else {
                data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                if (data.next) {
                    Dashboard.commandExecuted(req, true);
                    res.redirect('/dashboard/admin');
                };
            };
        });

        Dashboard.app.post('/dashboard/@me/servers/:guildID/execute/:action', Dashboard.checkAuth, function (req, res) {
            var next = req.query['next'];
            if (!next) next = false;
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let serv = client.guilds.get(req.params.guildID);
            Dashboard.onCommandExecute(req, data);
            if (data.customHtml) {
                if (next == 'true') {
                    data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                    if (data.next) {
                        Dashboard.commandExecuted(req, true);
                        res.redirect(`/dashboard/@me/servers/${serv.id}`);
                    };
                } else {
                    res.redirect(`/dashboard/@me/servers/${serv.id}/${data.name}`);
                };
            } else {
                data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                if (data.next) {
                    Dashboard.commandExecuted(req, true);
                    res.redirect(`/dashboard/@me/servers/${serv.id}/${data.name}`);
                };
            };
        });

        Dashboard.app.post('/api/admin/web', Dashboard.checkAuthOwner, function (req, res) {
            const dashboardConfigPath = require("path").join(__dirname, "../config.json");
            let config = require('../config.json.js.js');

            config.featureOne.name = req.body.featureOneName;
            config.featureOne.description = req.body.featureOneDescription;
            config.featureTwo.name = req.body.featureTwoName;
            config.featureTwo.description = req.body.featureTwoDescription;
            config.featureThree.name = req.body.featureThreeName;
            config.featureThree.description = req.body.featureThreeDescription;
            config.featureFour.name = req.body.featureFourName;
            config.featureFour.description = req.body.featureFourDescription;
            config.footerText = req.body.footerText;
            config.introText = req.body.introText;

            let settings = JSON.stringify(config);
            require("fs").writeFileSync(dashboardConfigPath, settings, "utf8");
            res.redirect('/');
        });
    };
};<commit_msg>Update dashboard.js (#21)<commit_after>module.exports = function (DBM) {
    const Dashboard = DBM.Dashboard;
    const client = DBM.Bot.bot;
    Dashboard.loadDashboard = function () {
        Dashboard.app.get('/dashboard/@me', Dashboard.checkAuth, function (req, res) {
            res.render('servers', {
                guilds: req.user.guilds.filter(u => (u.permissions & 2146958591) === 2146958591),
                user: req.user,
                config: Dashboard.config,
                client: DBM.Bot.bot,
                theme: Dashboard.theme(),
                req: req
            });
        });

        Dashboard.app.get('/dashboard/@me/servers/:guildID', Dashboard.checkAuth, function (req, res) {
            let serv = client.guilds.get(req.params.guildID);
            if (!serv) return res.redirect(`https://discordapp.com/oauth2/authorize?client_id=${DBM.Bot.bot.user.id}&scope=bot&permissions=2146958591&guild_id=${req.params.guildID}`);
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.dashboardMod == true) {
                    dashboardMods.push(data);
                };
            });
            let section = []
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.dashboardMod == true) {
                    section.push(action.section);
                };
            });
            if (!req.user.log) req.user.log = 'Command Executed';
            res.render('dashboardPanel', {
                client: DBM.Bot.bot,
                server: serv,
                dashboardMods: dashboardMods,
                customHtml: false,
                log: req.user.log,
                config: Dashboard.config,
                commandExecuted: req.user.commandExecuted,
                theme: Dashboard.theme(),
                sections: section,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/@me/servers/:guildID/:action', Dashboard.checkAuth, function (req, res) {
            let serv = client.guilds.get(req.params.guildID);
            if (!serv) return res.redirect(`https://discordapp.com/oauth2/authorize?client_id=${DBM.Bot.bot.user.id}&scope=bot&permissions=2146958591&guild_id=${req.params.guildID}`);
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.dashboardMod == true) dashboardMods.push(data);
            });
            let section = []
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.dashboardMod == true) {
                    section.push(action.section);
                };
            });
            res.render('dashboardPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: req.user.commandExecuted,
                customHtml: data.customHtml,
                action: data,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                server: serv,
                theme: Dashboard.theme(),
                sections: section,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/admin', Dashboard.checkAuthOwner, function (req, res) {
            let config = Dashboard.dashboardConfig();
            let dashboardMods = [];
            Dashboard.actions.forEach(data => {
                if (data.adminMod == true) dashboardMods.push(data);
            });
            if (!req.user.log) req.user.log = 'Command Executed';
            let actions = Dashboard.actions;
            let section = [];
            let extensions = [];
            actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.adminMod == true) {
                    section.push(action.section);
                };
            });

            actions.forEach(action => {
                if (action.extensionMod && action.customHtml) {
                    extensions.push(action);
                };
            });

            res.render('adminPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: req.user.commandExecuted,
                customHtml: false,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                theme: Dashboard.theme(),
                sections: section,
                extensions: extensions,
                app: Dashboard.app,
                req: req
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.get('/dashboard/admin/:action', Dashboard.checkAuthOwner, function (req, res) {
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let dashboardMods = [];

            Dashboard.actions.forEach(data => {
                if (data.adminMod == true) dashboardMods.push(data);
            });

            let section = [];
            let extensions = [];
            Dashboard.actions.forEach(action => {
                if (!section.includes(action.section) && action.routeMod == false && action.adminMod == true) {
                    section.push(action.section);
                }
            });

            Dashboard.actions.forEach(action => {
                if (action.extensionMod && action.customHtml) {
                    extensions.push(action);
                };
            });

            let passData = {}
            console.log(data.render(passData))
            res.render('adminPanel', {
                dashboardMods: dashboardMods,
                commandExecuted: false,
                customHtml: true,
                action: data,
                log: req.user.log,
                client: DBM.Bot.bot,
                config: Dashboard.config,
                theme: Dashboard.theme(),
                sections: section,
                extensions: extensions,
                app: Dashboard.app,
                req: req,
                render: data.render(passData)
            });
            Dashboard.commandExecuted(req, false);
        });

        Dashboard.app.post('/api/execute/:action', Dashboard.checkAuthOwner, function (req, res) {
            var next = req.query['next'];
            if (!next) next = false;
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let serv;
            Dashboard.onCommandExecute(req, data);
            if (data.customHtml) {
                if (next == 'true') {
                    data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                    if (data.next) {
                        Dashboard.commandExecuted(req, true);
                        res.redirect('/dashboard/admin');
                    };
                } else {
                    res.redirect(`/dashboard/admin/${data.name}`);
                };
            } else {
                data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                if (data.next) {
                    Dashboard.commandExecuted(req, true);
                    res.redirect('/dashboard/admin');
                };
            };
        });

        Dashboard.app.post('/dashboard/@me/servers/:guildID/execute/:action', Dashboard.checkAuth, function (req, res) {
            var next = req.query['next'];
            if (!next) next = false;
            var action = req.params.action;
            let data = Dashboard.actions.get(action);
            let serv = client.guilds.get(req.params.guildID);
            Dashboard.onCommandExecute(req, data);
            if (data.customHtml) {
                if (next == 'true') {
                    data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                    if (data.next) {
                        Dashboard.commandExecuted(req, true);
                        res.redirect(`/dashboard/@me/servers/${serv.id}`);
                    };
                } else {
                    res.redirect(`/dashboard/@me/servers/${serv.id}/${data.name}`);
                };
            } else {
                data.run(Dashboard.app, Dashboard.config, DBM, DBM.Bot.bot, req, res, serv);
                if (data.next) {
                    Dashboard.commandExecuted(req, true);
                    res.redirect(`/dashboard/@me/servers/${serv.id}/${data.name}`);
                };
            };
        });

        Dashboard.app.post('/api/admin/web', Dashboard.checkAuthOwner, function (req, res) {
            const dashboardConfigPath = require("path").join(__dirname, "../config.json");
            let config = require('../config.json');

            config.featureOne.name = req.body.featureOneName;
            config.featureOne.description = req.body.featureOneDescription;
            config.featureTwo.name = req.body.featureTwoName;
            config.featureTwo.description = req.body.featureTwoDescription;
            config.featureThree.name = req.body.featureThreeName;
            config.featureThree.description = req.body.featureThreeDescription;
            config.featureFour.name = req.body.featureFourName;
            config.featureFour.description = req.body.featureFourDescription;
            config.footerText = req.body.footerText;
            config.introText = req.body.introText;

            let settings = JSON.stringify(config);
            require("fs").writeFileSync(dashboardConfigPath, settings, "utf8");
            res.redirect('/');
        });
    };
};
<|endoftext|>


<commit_before>/*
 * @description: todo js
 * @refer: http://backbonejs.org/docs/todos.html
 */

$(function(){

	// TODO model

	var Todo = Backbone.Model.extend({
		defaults: function() {
			return {
				title: 'empty todo...',
				order: Todos.nextOrder(),
				done: false
			};
		},

		toggle: function() {
			this.save({
				done: !this.get('done')
			});
		}
	});

	// TODO list

	var TodoList = Backbone.Collection.extend({
		model: Todo,

		localStorage: new Backbone.LocalStorage('todoapp'),

		done: function() {
			return this.where({
				done: true
			});
		},

		remaining: function() {
			return this.where({
				done: false
			});
		},

		nextOrder: function() {
			if (!this.length) {
				return 1;
			}

			return this.last().get('order') + 1;
		},

		comparator: 'order'
	});

	var Todos = new TodoList;

	// TODO item view

	var TodoView = Backbone.View.extend({
		tagName: 'li',

		template: _.template($('#item-template').html()),

		events: {

		},

		initialize: function() {
			this.listenTo(this.model, 'change', this.render);
			this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			this.$el.toggleClass('done', this.model.get('done'));
			this.input = this.$('.edit');
			return this;
		},

		toggleDone: function() {
			this.model.toggle();
		},

		edit: function() {
			this.$el.addClass('editing');
			this.input.focus();
		},

		close: function() {
			var value = this.input.val();
			if (!value) {
				this.clear();
			} else{
				this.model.save({
					title: value
				});
				this.$el.removeClass('editing');
			};
		},

		updateOnEnter: function(e) {
			if (e.keyCode == 13) {
				this.close();
			}
		},

		clear: function() {
			this.model.destroy();
		}

	});

	// The application

	var AppView = Backbone.View.extend({

		el: $('todoapp'),

		statsTemplate: _.template($('#stats-template').html()),

		events: {
			'keypress #new-todo': 'createOnEnter',
			'click #clear-completed': 'clearCompleted',
			'click #toggle-all': 'toggleAllComplete'
		},

		initialize: function() {

			this.input = this.$('#new-todo');
			// this.allCheckbox = this.$('#toggle-all')[0];
			this.allCheckbox = $('#toggle-all');

			this.footer = this.$('footer');
			this.main = $('#main');

			this.listenTo(Todos, 'add', this.addOne);
			this.listenTo(Todos, 'reset', this.addAll);
			this.listenTo(Todos, 'all', this.render);

			Todos.fetch();
		},

		render: function() {
			var done = Todos.done().length;
			var remaining = Todos.remaining().length;

			if(Todos.length) {
				this.main.show();
				this.footer.show();
				this.footer.html(this.statsTemplate({
					done: done,
					remaining: remaining
				}));
			} else {
				this.main.hide();
				this.footer.hide();
			}

			this.allCheckbox.checked = !remaining;
		},

		addOne: function(todo) {
			var view = new TodoView({ model: todo });
			this.$('#todo-list').append(view.render().el);
		},

		addAll: function() {
			Todos.each(this.addOne, this);
		},

		createOnEnter: function(e) {
			if (e.keyCode != 13)
				return;
			if (!this.input.val())
				return;

			Todos.create({title: this.input.val()});
			this.input.val('');
		},

		clearCompleted: function() {
			_.invoke(Todos.done(), 'destroy');
			return false;
		},

		toggleAllComplete: function() {
			var done = this.allCheckbox.checked;
			Todos.each(function(todo) {
				todo.save({'done': done});
			});
		}
	});

	// Finnaly, creating the App
	var App = new AppView;

});<commit_msg>add events<commit_after>/*
 * @description: todo js
 * @refer: http://backbonejs.org/docs/todos.html
 */

$(function(){

	// TODO model

	var Todo = Backbone.Model.extend({
		defaults: function() {
			return {
				title: 'empty todo...',
				order: Todos.nextOrder(),
				done: false
			};
		},

		toggle: function() {
			this.save({
				done: !this.get('done')
			});
		}
	});

	// TODO list

	var TodoList = Backbone.Collection.extend({
		model: Todo,

		localStorage: new Backbone.LocalStorage('todoapp'),

		done: function() {
			return this.where({
				done: true
			});
		},

		remaining: function() {
			return this.where({
				done: false
			});
		},

		nextOrder: function() {
			if (!this.length) {
				return 1;
			}

			return this.last().get('order') + 1;
		},

		comparator: 'order'
	});

	var Todos = new TodoList;

	// TODO item view

	var TodoView = Backbone.View.extend({
		tagName: 'li',

		template: _.template($('#item-template').html()),

		events: {
			'click .toggle': 'toggleDone',
			'dblclick .view': 'edit',
			'click a.destroy': 'clear',
			'keypress .edit': 'updateOnEnter',
			'blur .edit': 'close'
		},

		initialize: function() {
			this.listenTo(this.model, 'change', this.render);
			this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			this.$el.toggleClass('done', this.model.get('done'));
			this.input = this.$('.edit');
			return this;
		},

		toggleDone: function() {
			this.model.toggle();
		},

		edit: function() {
			this.$el.addClass('editing');
			this.input.focus();
		},

		close: function() {
			var value = this.input.val();
			if (!value) {
				this.clear();
			} else{
				this.model.save({
					title: value
				});
				this.$el.removeClass('editing');
			};
		},

		updateOnEnter: function(e) {
			if (e.keyCode == 13) {
				this.close();
			}
		},

		clear: function() {
			this.model.destroy();
		}

	});

	// The application

	var AppView = Backbone.View.extend({

		el: $('todoapp'),

		statsTemplate: _.template($('#stats-template').html()),

		events: {
			'keypress #new-todo': 'createOnEnter',
			'click #clear-completed': 'clearCompleted',
			'click #toggle-all': 'toggleAllComplete'
		},

		initialize: function() {

			this.input = this.$('#new-todo');
			// this.allCheckbox = this.$('#toggle-all')[0];
			this.allCheckbox = $('#toggle-all');

			this.footer = this.$('footer');
			this.main = $('#main');

			this.listenTo(Todos, 'add', this.addOne);
			this.listenTo(Todos, 'reset', this.addAll);
			this.listenTo(Todos, 'all', this.render);

			Todos.fetch();
		},

		render: function() {
			var done = Todos.done().length;
			var remaining = Todos.remaining().length;

			if(Todos.length) {
				this.main.show();
				this.footer.show();
				this.footer.html(this.statsTemplate({
					done: done,
					remaining: remaining
				}));
			} else {
				this.main.hide();
				this.footer.hide();
			}

			this.allCheckbox.checked = !remaining;
		},

		addOne: function(todo) {
			var view = new TodoView({ model: todo });
			this.$('#todo-list').append(view.render().el);
		},

		addAll: function() {
			Todos.each(this.addOne, this);
		},

		createOnEnter: function(e) {
			if (e.keyCode != 13)
				return;
			if (!this.input.val())
				return;

			Todos.create({title: this.input.val()});
			this.input.val('');
		},

		clearCompleted: function() {
			_.invoke(Todos.done(), 'destroy');
			return false;
		},

		toggleAllComplete: function() {
			var done = this.allCheckbox.checked;
			Todos.each(function(todo) {
				todo.save({'done': done});
			});
		}
	});

	// Finnaly, creating the App
	var App = new AppView;

});<|endoftext|>


<commit_before>(function($) {

$("#realtime-widget").remove();
var container = $('
').css({
	position: "fixed",
	left: 0,
	bottom: 0,
	"background-color": "#ccc",
	width: "100%",
	"border-top": "solid 2px black"
}).appendTo(document.body)[0];

var height = 130;

var widget = $('').appendTo(container);
$(widget).css({
	position: "relative",
	height: height,
	"z-index": 0,
	width: "100%"
});

$('<button>real time</button>').click(function(ev) {
	$(widget).toggle();
}).css({
	position: "absolute", right: 0, bottom: "0px",
	"background": "none",
	"z-index": 2,
	"text-indent": -99,
	bottom: 0,
	border: "none",
	"background-repeat": "no-repeat",
	cursor: "pointer",
	"background-image": "url(http://following.tiddlyspace.com/SiteIcon)"
}).appendTo(container);

})(jQuery);<commit_msg>add padding bottom to offset the iframe and allow scrolling to bottom of page<commit_after>(function($) {

$("#realtime-widget").remove();
var container = $('
').css({
	position: "fixed",
	left: 0,
	bottom: 0,
	"background-color": "#ccc",
	width: "100%",
	"border-top": "solid 2px black"
}).appendTo(document.body)[0];

var height = 130;

var widget = $('').appendTo(container);
$(widget).css({
	position: "relative",
	height: height,
	"z-index": 0,
	width: "100%"
});

$('<button>real time</button>').click(function(ev) {
	$(widget).toggle();
}).css({
	position: "absolute", right: 0, bottom: "0px",
	"background": "none",
	"z-index": 2,
	"text-indent": -99,
	bottom: 0,
	border: "none",
	"background-repeat": "no-repeat",
	cursor: "pointer",
	"background-image": "url(http://following.tiddlyspace.com/SiteIcon)"
}).appendTo(container);

$(document.body).css({ "padding-bottom": height });
})(jQuery);
<|endoftext|>


<commit_before>/**
 * API function to create fetch store tests.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';
import isPlainObject from 'lodash/isPlainObject';

/**
 * WordPress dependencies
 */
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import {
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from 'tests/js/utils';
import { createFetchStore } from './create-fetch-store';

const STORE_NAME = 'test/some-data';
const STORE_PARAMS = {
	baseName: 'getSomeData',
	controlCallback: ( params ) => {
		const { aParam, objParam } = params;
		return API.get( 'core', 'test', 'some-data', {
			aParam,
			objParam,
		} );
	},
	reducerCallback: ( state, response, params ) => {
		const { aParam } = params;
		return {
			...state,
			data: {
				...( state.data || {} ),
				[ aParam ]: response,
			},
		};
	},
	argsToParams: ( objParam, aParam ) => {
		invariant( isPlainObject( objParam ), 'objParam is required.' );
		invariant( aParam !== undefined, 'aParam is required.' );
		return {
			objParam,
			aParam,
		};
	},
};

describe( 'createFetchStore store', () => {
	let dispatch;
	let registry;
	let select;
	let storeDefinition;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createRegistry();

		storeDefinition = createFetchStore( STORE_PARAMS );
		registry.registerStore( STORE_NAME, storeDefinition );
		dispatch = registry.dispatch( STORE_NAME );
		store = registry.stores[ STORE_NAME ].store;
		select = registry.select( STORE_NAME );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
	} );

	describe( 'actions', () => {
		it( 'includes the expected actions', () => {
			const fetchStoreDefinition = createFetchStore( {
				baseName: 'SaveSomeData',
				controlCallback: async () => true,
			} );

			expect( Object.keys( fetchStoreDefinition.actions ) ).toEqual( [
				'fetchSaveSomeData',
				'receiveSaveSomeData',
			] );
		} );

		describe( 'fetch', () => {
			it( 'validates parameters based on argsToParams', () => {
				const consoleErrorSpy = jest.spyOn( global.console, 'error' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData();
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'objParam is required.' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData( 123 );
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'objParam is required.' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData( {} );
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'aParam is required.' );

				consoleErrorSpy.mockClear();
			} );

			it( 'yields the expected actions for an arguments error', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					argsToParams: ( requiredParam ) => {
						invariant( requiredParam, 'requiredParam is required.' );
						return {
							requiredParam,
						};
					},
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				// Catch invariant to get exactly the error we expect.
				let error;
				try {
					muteConsole( 'error' );
					invariant( false, 'requiredParam is required.' );
				} catch ( err ) {
					error = err;
				}

				expect( action.next().value ).toEqual( {
					response: undefined,
					error,
				} );
			} );

			it( 'yields the expected actions for a success request', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				expect( action.next().value.type ).toEqual( 'START_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FETCH_SAVE_SOME_DATA' );
				expect( action.next( 42 ).value.type ).toEqual( 'RECEIVE_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FINISH_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value ).toEqual( {
					response: 42,
					error: undefined,
				} );
			} );

			it( 'yields the expected actions for an error request', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				const error = {
					code: 'this-went-wrong',
					message: 'This went wrong.',
				};

				expect( action.next().value.type ).toEqual( 'START_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FETCH_SAVE_SOME_DATA' );
				expect( action.throw( error ).value.type ).toEqual( 'CATCH_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value ).toEqual( {
					response: undefined,
					error,
				} );
			} );

			it( 'makes a network request based on controlCallback', async () => {
				const expectedResponse = 'response-value';
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						JSON.stringify( expectedResponse ),
						{ status: 200 }
					);

				const { response, error } = await dispatch.fetchGetSomeData( {}, 'value-to-key-response-by' );

				expect( error ).toEqual( undefined );
				expect( response ).toEqual( expectedResponse );
				expect( store.getState().data ).toEqual( {
					'value-to-key-response-by': expectedResponse,
				} );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const errorResponse = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						JSON.stringify( errorResponse ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				const { response, error } = await dispatch.fetchGetSomeData( {}, 'value-to-key-response-by' );

				expect( error ).toEqual( errorResponse );
				expect( response ).toEqual( undefined );
				expect( store.getState().data ).toEqual( undefined );
			} );

			it( 'sets flag for request being in progress', async () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						// Just return any value here.
						JSON.stringify( { someValue: 42 } ),
						{ status: 200 }
					);

				const requestArgs = [ {}, 'aValue' ];

				// Initially the request is not in progress..
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( false );

				dispatch.fetchGetSomeData( ...requestArgs );

				// Now it should be in progress.
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( true );

				// A request for other arguments however is not in progress.
				expect( select.isFetchingGetSomeData( {}, 'anotherValue' ) ).toEqual( false );

				await subscribeUntil( registry,
					() => store.getState().data !== undefined,
				);

				// As the data has been received, the request is now no longer in progress.
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( false );
			} );
		} );

		describe( 'receive', () => {
			it( 'requires params if argsToParams is provided', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					argsToParams: ( requiredParam ) => {
						invariant( requiredParam, 'requiredParam is required.' );
						return {
							requiredParam,
						};
					},
				} );

				expect( () => {
					const response = {};
					fetchStoreDefinition.actions.receiveSaveSomeData( response );
				} ).toThrow( 'params is required.' );
			} );

			it( 'does not require params if argsToParams is not provided', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					reducerCallback: ( state ) => state,
				} );

				expect( () => {
					const response = {};
					fetchStoreDefinition.actions.receiveSaveSomeData( response );
				} ).not.toThrow( 'params is required.' );
			} );
		} );
	} );

	describe( 'selectors', () => {
		it( 'includes the expected selectors', () => {
			const fetchStoreDefinition = createFetchStore( {
				baseName: 'SaveSomeData',
				controlCallback: async () => true,
			} );

			expect( Object.keys( fetchStoreDefinition.selectors ) ).toEqual( [
				'isFetchingSaveSomeData',
			] );
		} );
	} );
} );
<commit_msg>Use relative import for tests/js/utils.<commit_after>/**
 * API function to create fetch store tests.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';
import isPlainObject from 'lodash/isPlainObject';

/**
 * WordPress dependencies
 */
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import {
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from '../../../../tests/js/utils';
import { createFetchStore } from './create-fetch-store';

const STORE_NAME = 'test/some-data';
const STORE_PARAMS = {
	baseName: 'getSomeData',
	controlCallback: ( params ) => {
		const { aParam, objParam } = params;
		return API.get( 'core', 'test', 'some-data', {
			aParam,
			objParam,
		} );
	},
	reducerCallback: ( state, response, params ) => {
		const { aParam } = params;
		return {
			...state,
			data: {
				...( state.data || {} ),
				[ aParam ]: response,
			},
		};
	},
	argsToParams: ( objParam, aParam ) => {
		invariant( isPlainObject( objParam ), 'objParam is required.' );
		invariant( aParam !== undefined, 'aParam is required.' );
		return {
			objParam,
			aParam,
		};
	},
};

describe( 'createFetchStore store', () => {
	let dispatch;
	let registry;
	let select;
	let storeDefinition;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createRegistry();

		storeDefinition = createFetchStore( STORE_PARAMS );
		registry.registerStore( STORE_NAME, storeDefinition );
		dispatch = registry.dispatch( STORE_NAME );
		store = registry.stores[ STORE_NAME ].store;
		select = registry.select( STORE_NAME );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
	} );

	describe( 'actions', () => {
		it( 'includes the expected actions', () => {
			const fetchStoreDefinition = createFetchStore( {
				baseName: 'SaveSomeData',
				controlCallback: async () => true,
			} );

			expect( Object.keys( fetchStoreDefinition.actions ) ).toEqual( [
				'fetchSaveSomeData',
				'receiveSaveSomeData',
			] );
		} );

		describe( 'fetch', () => {
			it( 'validates parameters based on argsToParams', () => {
				const consoleErrorSpy = jest.spyOn( global.console, 'error' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData();
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'objParam is required.' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData( 123 );
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'objParam is required.' );

				muteConsole( 'error' );
				dispatch.fetchGetSomeData( {} );
				expect( consoleErrorSpy ).toHaveBeenCalledWith( 'aParam is required.' );

				consoleErrorSpy.mockClear();
			} );

			it( 'yields the expected actions for an arguments error', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					argsToParams: ( requiredParam ) => {
						invariant( requiredParam, 'requiredParam is required.' );
						return {
							requiredParam,
						};
					},
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				// Catch invariant to get exactly the error we expect.
				let error;
				try {
					muteConsole( 'error' );
					invariant( false, 'requiredParam is required.' );
				} catch ( err ) {
					error = err;
				}

				expect( action.next().value ).toEqual( {
					response: undefined,
					error,
				} );
			} );

			it( 'yields the expected actions for a success request', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				expect( action.next().value.type ).toEqual( 'START_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FETCH_SAVE_SOME_DATA' );
				expect( action.next( 42 ).value.type ).toEqual( 'RECEIVE_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FINISH_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value ).toEqual( {
					response: 42,
					error: undefined,
				} );
			} );

			it( 'yields the expected actions for an error request', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
				} );

				const action = fetchStoreDefinition.actions.fetchSaveSomeData();

				const error = {
					code: 'this-went-wrong',
					message: 'This went wrong.',
				};

				expect( action.next().value.type ).toEqual( 'START_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value.type ).toEqual( 'FETCH_SAVE_SOME_DATA' );
				expect( action.throw( error ).value.type ).toEqual( 'CATCH_FETCH_SAVE_SOME_DATA' );
				expect( action.next().value ).toEqual( {
					response: undefined,
					error,
				} );
			} );

			it( 'makes a network request based on controlCallback', async () => {
				const expectedResponse = 'response-value';
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						JSON.stringify( expectedResponse ),
						{ status: 200 }
					);

				const { response, error } = await dispatch.fetchGetSomeData( {}, 'value-to-key-response-by' );

				expect( error ).toEqual( undefined );
				expect( response ).toEqual( expectedResponse );
				expect( store.getState().data ).toEqual( {
					'value-to-key-response-by': expectedResponse,
				} );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const errorResponse = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						JSON.stringify( errorResponse ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				const { response, error } = await dispatch.fetchGetSomeData( {}, 'value-to-key-response-by' );

				expect( error ).toEqual( errorResponse );
				expect( response ).toEqual( undefined );
				expect( store.getState().data ).toEqual( undefined );
			} );

			it( 'sets flag for request being in progress', async () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/core\/test\/data\/some-data/
					)
					.mockResponseOnce(
						// Just return any value here.
						JSON.stringify( { someValue: 42 } ),
						{ status: 200 }
					);

				const requestArgs = [ {}, 'aValue' ];

				// Initially the request is not in progress..
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( false );

				dispatch.fetchGetSomeData( ...requestArgs );

				// Now it should be in progress.
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( true );

				// A request for other arguments however is not in progress.
				expect( select.isFetchingGetSomeData( {}, 'anotherValue' ) ).toEqual( false );

				await subscribeUntil( registry,
					() => store.getState().data !== undefined,
				);

				// As the data has been received, the request is now no longer in progress.
				expect( select.isFetchingGetSomeData( ...requestArgs ) ).toEqual( false );
			} );
		} );

		describe( 'receive', () => {
			it( 'requires params if argsToParams is provided', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					argsToParams: ( requiredParam ) => {
						invariant( requiredParam, 'requiredParam is required.' );
						return {
							requiredParam,
						};
					},
				} );

				expect( () => {
					const response = {};
					fetchStoreDefinition.actions.receiveSaveSomeData( response );
				} ).toThrow( 'params is required.' );
			} );

			it( 'does not require params if argsToParams is not provided', () => {
				const fetchStoreDefinition = createFetchStore( {
					baseName: 'SaveSomeData',
					controlCallback: async () => true,
					reducerCallback: ( state ) => state,
				} );

				expect( () => {
					const response = {};
					fetchStoreDefinition.actions.receiveSaveSomeData( response );
				} ).not.toThrow( 'params is required.' );
			} );
		} );
	} );

	describe( 'selectors', () => {
		it( 'includes the expected selectors', () => {
			const fetchStoreDefinition = createFetchStore( {
				baseName: 'SaveSomeData',
				controlCallback: async () => true,
			} );

			expect( Object.keys( fetchStoreDefinition.selectors ) ).toEqual( [
				'isFetchingSaveSomeData',
			] );
		} );
	} );
} );
<|endoftext|>


<commit_before>var check = require('check-types');
var Q = require('q');
var dexec = require('deferred-exec');

function proudBadge(username, n, filename) {
  check.verify.unemptyString(username, 'expected username');
  check.verify.number(n, 'expected number of downloads');
  check.verify.unemptyString(filename, 'expected filename');

  var defer = Q.defer();

  dexec('convert -background lightblue -fill black -font Helvetica ' +
    '-size 280x72 -gravity center label:\'' + username + ' proud ' + n + '\nNPM downloads\' ' + filename)
  .done(function (stdout, stderr) {
    defer.resolve(stdout);
  })
  .fail(function (err) {
    console.error('could not get generate badge');
    console.error(err);
    defer.reject(err);
  });

  return defer.promise;
}

module.exports = proudBadge;
<commit_msg>added frame around<commit_after>var check = require('check-types');
var Q = require('q');
var dexec = require('deferred-exec');

function proudBadge(username, n, filename) {
  check.verify.unemptyString(username, 'expected username');
  check.verify.number(n, 'expected number of downloads');
  check.verify.unemptyString(filename, 'expected filename');

  var defer = Q.defer();

  dexec('convert -background lightblue -fill black -font Helvetica ' +
    '-size 280x72 -gravity center label:\'' + username + ' proud ' + n + '\nNPM downloads\' ' +
    '-frame 2x2+2+0 ' +
    filename)
  .done(function (stdout, stderr) {
    defer.resolve(stdout);
  })
  .fail(function (err) {
    console.error('could not get generate badge');
    console.error(err);
    defer.reject(err);
  });

  return defer.promise;
}

module.exports = proudBadge;
<|endoftext|>