<commit_before>/***
 * This is a "wrapper" of sorts, for the Khan Academy API.
 * Anything relating to the Khan Academy API should be placed in this file.
***/
window.KA_API = (function() {
    /* Function wrapper to create KA_API */
    /* jQuery is required for [most] all of these. So if it's object is not found, exit the function. */
    if (!window.jQuery) {
        console.log("Needs jQuery");
        return;
    }

    /* Everything from this namespace will be placed in the object that is returned. */
    return {
        /* Khan Academy API Urls */
        urls: {
            /* For getting contests: */
            spotlight: "https://www.khanacademy.org/api/internal/scratchpads/top?casing=camel&topic_id=xffde7c31&sort=4&limit=40000&page=0&lang=en&_=1436581332879",
            /* For getting contest entries where contest has ID of programID */
            spinoffs: function(programID) {
                return "https://www.khanacademy.org/api/internal/scratchpads/{PROGRAM}/top-forks?casing=camel&sort=2&limit=300000&page=0&lang=en".replace("{PROGRAM}", programID);
            },
            scratchpadInfo: function(scratchpadId) {
                return "https://www.khanacademy.org/api/labs/scratchpads/{SCRATCHPAD}".replace("{SCRATCHPAD}", scratchpadId);
            }
        },
        /* This function gets all the entries for a specific contest, and passes them into the callback. */
        getContestEntries: function(contestID, callback) {
            /* Any entries that we find, will be put into this object. (We'll also pass this object into callback.) */
            var entries = {};

            /* Send AJAX request for getting all the entries to the desired contest */
            var apiQuery = $.ajax({
                type: 'GET',
                url: this.urls.spinoffs(contestID),
                async: true,
                complete: function(apiResponse) {
                    /* When the AJAX request finishes */
                    /* allPrograms is a list of all of the contest entries */
                    var allPrograms = apiResponse.responseJSON.scratchpads

                    /* Loop through allPrograms */
                    for (var i = 0; i < allPrograms.length; i++) {
                        /* Program ID for this spin-off */
                        var id = allPrograms[i].url.split("/")[5];

                        /* Add JSON object for this spin-off into entries */
                        entries[id] = {
                            /* Program ID */
                            id: id,
                            /* Program Title */
                            name: allPrograms[i].translatedTitle,
                            /* Program Scores */
                            scores: {
                                rubric: {
                                    "Clean_Code": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Creativity": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Level": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Overall": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "NumberOfJudges": 1,
                                    "judgesWhoVoted": [ ]
                                }
                            }
                        };
                    }
                    /* Finally, pass entries into callback */
                    callback(entries);
                }
            });
        },
        /* This function gets all of Pamela's contest programs from Khan Academy and passes them into the callback function. */
        getContests: function(callback) {
            /* This Bool is true iff the first AJAX request has finished. */
            var apiQueryDone = false;
            /* Any contests that we find, will be put into this object. (We'll also pass this object into callback.) */
            var allContests = {};

            /* Send AJAX request to get all the contests from Khan Academy */
            var apiQuery = $.ajax({
                type: 'GET',
                url: this.urls.spotlight,
                async: true,
                complete: function(apiResponse) {
                    /* When the AJAX request finishes */
                    /* allPrograms is a list of all of the contest entries */
                    var allPrograms = apiResponse.responseJSON.scratchpads;

                    /* Loop through allPrograms */
                    for (var i = 0; i < allPrograms.length; i++) {
                        /* For now, let's only accept contests from pamela. Also, all contests must have "Contest" in their title. */
                        if (allPrograms[i].authorNickname.match("pamela") !== null && allPrograms[i].translatedTitle.match("Contest") !== null) {
                            var programID = allPrograms[i].url.split("/")[5];
                            /* Make an empty object in allContests to alert the setTimeout() function below that such an object has yet to be set. */
                            allContests[programID] = {};
                            /* Put this in a function wrapper so the parameters will be saved. */
                            (function(programID, scratchpad, contests) {
                                $.ajax({
                                    type: 'GET',
                                    url: KA_API.urls.scratchpadInfo(programID),
                                    async: true,
                                    complete: function(scratchpadData) {
                                        /* Add in a JSON object for this contest into contests */
                                        contests[programID] = {
                                            /* Program ID */
                                            id: programID,
                                            /* Program Title */
                                            name: scratchpad.translatedTitle,
                                            /* Program Icon */
                                            img: scratchpad.thumb,
                                            /* Contest Description */
                                            desc: scratchpadData.responseJSON.description
                                        };

                                        /* Fetch the contest entries for this contest and when done, set the entries property within the above JSON object. */
                                        KA_API.getContestEntries(contests[programID].id, function(entries) {
                                            contests[programID].entries = entries;
                                        });
                                    }
                                });
                            })(programID, allPrograms[i], allContests);
                            /* Pass in the parameters to this function as above. */
                        }
                    }
                    /* Once we're done with the AJAX request, set apiQueryDone to true. */
                    apiQueryDone = true;
                }
            });

            /* Check to see if we're done every second; if we are, invoke the callback function. (Idea from @noble-mushtak) */
            var finishTimeout = setInterval(function() {
                if (apiQueryDone) {
                    /* If the first AJAX request has finished, make sure all of the other AJAX requests have finished. If we find a contest without the entries property, we know their AJAX request has not finished, so we return. */
                    for (var i in allContests) {
                        if (!allContests[i].hasOwnProperty("entries")) return;
                    }

                    /* At this point, we have made sure the request has finished, so we make a log in the console, stop looping this asynchronous function, and finally pass contests into callback. */
                    console.log("getContests() finished!");
                    /* Make sure clearTimeout() is called first. We don't know how long callback will take and if callback takes more than a second, then callback will be called multiple times. */
                    clearInterval(finishTimeout);
                    callback(allContests);
                }
            }, 1000);
        }
    };
})();<commit_msg>Minor change<commit_after>/***
 * This is a "wrapper" of sorts, for the Khan Academy API.
 * Anything relating to the Khan Academy API should be placed in this file.
***/
window.KA_API = (function() {
    /* Function wrapper to create KA_API */
    /* jQuery is required for [most] all of these. So if it's object is not found, exit the function. */
    if (!window.jQuery) {
        console.log("Needs jQuery");
        return;
    }

    /* Everything from this namespace will be placed in the object that is returned. */
    return {
        /* Khan Academy API Urls */
        urls: {
            /* For getting contests: */
            spotlight: "https://www.khanacademy.org/api/internal/scratchpads/top?casing=camel&topic_id=xffde7c31&sort=4&limit=40000&page=0&lang=en&_=1436581332879",
            /* For getting contest entries where contest has ID of programID */
            spinoffs: function(programID) {
                return "https://www.khanacademy.org/api/internal/scratchpads/{PROGRAM}/top-forks?casing=camel&sort=2&limit=300000&page=0&lang=en".replace("{PROGRAM}", programID);
            },
            scratchpadInfo: function(scratchpadId) {
                return "https://www.khanacademy.org/api/labs/scratchpads/{SCRATCHPAD}".replace("{SCRATCHPAD}", scratchpadId);
            }
        },
        /* This function gets all the entries for a specific contest, and passes them into the callback. */
        getContestEntries: function(contestID, callback) {
            /* Any entries that we find, will be put into this object. (We'll also pass this object into callback.) */
            var entries = {};

            /* Send AJAX request for getting all the entries to the desired contest */
            var apiQuery = $.ajax({
                type: 'GET',
                url: this.urls.spinoffs(contestID),
                async: true,
                complete: function(apiResponse) {
                    /* When the AJAX request finishes */
                    /* allPrograms is a list of all of the contest entries */
                    var allPrograms = apiResponse.responseJSON.scratchpads

                    /* Loop through allPrograms */
                    for (var i = 0; i < allPrograms.length; i++) {
                        /* Program ID for this spin-off */
                        var id = allPrograms[i].url.split("/")[5];

                        /* Add JSON object for this spin-off into entries */
                        entries[id] = {
                            /* Program ID */
                            id: id,
                            /* Program Title */
                            name: allPrograms[i].translatedTitle,
                            /* Program Image */
                            img: allPrograms[i].thumb,
                            /* Program Scores */
                            scores: {
                                rubric: {
                                    "Clean_Code": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Creativity": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Level": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "Overall": {
                                        "rough": 1,
                                        "avg": 1
                                    },
                                    "NumberOfJudges": 1,
                                    "judgesWhoVoted": [ ]
                                }
                            }
                        };
                    }
                    /* Finally, pass entries into callback */
                    callback(entries);
                }
            });
        },
        /* This function gets all of Pamela's contest programs from Khan Academy and passes them into the callback function. */
        getContests: function(callback) {
            /* This Bool is true iff the first AJAX request has finished. */
            var apiQueryDone = false;
            /* Any contests that we find, will be put into this object. (We'll also pass this object into callback.) */
            var allContests = {};

            /* Send AJAX request to get all the contests from Khan Academy */
            var apiQuery = $.ajax({
                type: 'GET',
                url: this.urls.spotlight,
                async: true,
                complete: function(apiResponse) {
                    /* When the AJAX request finishes */
                    /* allPrograms is a list of all of the contest entries */
                    var allPrograms = apiResponse.responseJSON.scratchpads;

                    /* Loop through allPrograms */
                    for (var i = 0; i < allPrograms.length; i++) {
                        /* For now, let's only accept contests from pamela. Also, all contests must have "Contest" in their title. */
                        if (allPrograms[i].authorNickname.match("pamela") !== null && allPrograms[i].translatedTitle.match("Contest") !== null) {
                            var programID = allPrograms[i].url.split("/")[5];
                            /* Make an empty object in allContests to alert the setTimeout() function below that such an object has yet to be set. */
                            allContests[programID] = {};
                            /* Put this in a function wrapper so the parameters will be saved. */
                            (function(programID, scratchpad, contests) {
                                $.ajax({
                                    type: 'GET',
                                    url: KA_API.urls.scratchpadInfo(programID),
                                    async: true,
                                    complete: function(scratchpadData) {
                                        /* Add in a JSON object for this contest into contests */
                                        contests[programID] = {
                                            /* Program ID */
                                            id: programID,
                                            /* Program Title */
                                            name: scratchpad.translatedTitle,
                                            /* Program Icon */
                                            img: scratchpad.thumb,
                                            /* Contest Description */
                                            desc: scratchpadData.responseJSON.description
                                        };

                                        /* Fetch the contest entries for this contest and when done, set the entries property within the above JSON object. */
                                        KA_API.getContestEntries(contests[programID].id, function(entries) {
                                            contests[programID].entries = entries;
                                        });
                                    }
                                });
                            })(programID, allPrograms[i], allContests);
                            /* Pass in the parameters to this function as above. */
                        }
                    }
                    /* Once we're done with the AJAX request, set apiQueryDone to true. */
                    apiQueryDone = true;
                }
            });

            /* Check to see if we're done every second; if we are, invoke the callback function. (Idea from @noble-mushtak) */
            var finishTimeout = setInterval(function() {
                if (apiQueryDone) {
                    /* If the first AJAX request has finished, make sure all of the other AJAX requests have finished. If we find a contest without the entries property, we know their AJAX request has not finished, so we return. */
                    for (var i in allContests) {
                        if (!allContests[i].hasOwnProperty("entries")) return;
                    }

                    /* At this point, we have made sure the request has finished, so we make a log in the console, stop looping this asynchronous function, and finally pass contests into callback. */
                    console.log("getContests() finished!");
                    /* Make sure clearTimeout() is called first. We don't know how long callback will take and if callback takes more than a second, then callback will be called multiple times. */
                    clearInterval(finishTimeout);
                    callback(allContests);
                }
            }, 1000);
        }
    };
})();<|endoftext|>


<commit_before>
/**
 * Active dialog.
 */

var active;

/**
 * Expose `Dialog`.
 */

exports.Dialog = Dialog;

/**
 * Return a new `Dialog` with the given
 * (optional) `title` and `msg`.
 *
 * @param {String} title or msg
 * @param {String} msg
 * @return {Dialog}
 * @api public
 */

exports.dialog = function(title, msg){
  switch (arguments.length) {
    case 2:
      return new Dialog({ title: title, message: msg });
    case 1:
      return new Dialog({ message: title });
  }
};

/**
 * Initialize a new `Dialog`.
 *
 * Options:
 *
 *    - `title` dialog title
 *    - `message` a message to display
 *
 * Emits:
 *
 *    - `show` when visible
 *    - `hide` when hidden
 *
 * @param {Object} options
 * @api public
 */

function Dialog(options) {
  ui.Emitter.call(this);
  options = options || {};
  this.template = html;
  this.el = $(this.template);
  this.render(options);
  if (active && !active.hiding) active.hide();
  if (Dialog.effect) this.effect(Dialog.effect);
  active = this;
};

/**
 * Inherit from `Emitter.prototype`.
 */

Dialog.prototype = new ui.Emitter;

/**
 * Render with the given `options`.
 *
 * @param {Object} options
 * @api public
 */

Dialog.prototype.render = function(options){
  var el = this.el
    , title = options.title
    , msg = options.message
    , self = this;

  el.find('.close').click(function(){
    self.emit('close');
    self.hide();
    return false;
  });

  el.find('h1').text(title);
  if (!title) el.find('h1').remove();

  // message
  if ('string' == typeof msg) {
    el.find('p').text(msg);
  } else if (msg) {
    el.find('p').replaceWith(msg.el || msg);
  }

  setTimeout(function(){
    el.removeClass('hide');
  }, 0);
};

/**
 * Enable the dialog close link.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.closable = function(){
  this.el.addClass('closable');
  return this;
};

/**
 * Set the effect to `type`.
 *
 * @param {String} type
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.effect = function(type){
  this._effect = type;
  this.el.addClass(type);
  return this;
};

/**
 * Make it modal!
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.modal = function(){
  this._overlay = ui.overlay();
  return this;
};

/**
 * Add an overlay.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.overlay = function(){
  var self = this;
  this._overlay = ui
    .overlay({ closable: true })
    .on('hide', function(){
      self.closedOverlay = true;
      self.hide();
    });
  return this;
};

/**
 * Close the dialog when the escape key is pressed.
 *
 * @api private
 */

Dialog.prototype.escapable = function(){
  var self = this;
  $(document).bind('keydown.dialog', function(e){
    if (27 != e.which) return;
    $(this).unbind('keydown.dialog');
    self.hide();
  });
};

/**
 * Show the dialog.
 *
 * Emits "show" event.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.show = function(){
  var overlay = this._overlay;

  this.emit('show');

  if (overlay) {
    overlay.show();
    this.el.addClass('modal');
  }

  // escape
  if (!overlay || overlay.closable) this.escapable();

  this.el.appendTo('body');
  this.el.css({ marginLeft: -(this.el.width() / 2) + 'px' });
  this.emit('show');
  return this;
};

/**
 * Hide the dialog with optional delay of `ms`,
 * otherwise the dialog is removed immediately.
 *
 * Emits "hide" event.
 *
 * @return {Number} ms
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.hide = function(ms){
  var self = this;

  // prevent thrashing
  this.hiding = true;

  // duration
  if (ms) {
    setTimeout(function(){
      self.hide();
    }, ms);
    return this;
  }

  // hide / remove
  this.el.addClass('hide');
  if (this._effect) {
    setTimeout(function(self){
      self.remove();
    }, 500, this);
  } else {
    self.remove();
  }

  // modal
  if (this._overlay && !self.closedOverlay) this._overlay.hide();

  return this;
};

/**
 * Hide the dialog without potential animation.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.remove = function(){
  this.emit('hide');
  this.el.remove();
  return this;
};
<commit_msg>Fix IE8 error when a dialog with effect closes<commit_after>
/**
 * Active dialog.
 */

var active;

/**
 * Expose `Dialog`.
 */

exports.Dialog = Dialog;

/**
 * Return a new `Dialog` with the given
 * (optional) `title` and `msg`.
 *
 * @param {String} title or msg
 * @param {String} msg
 * @return {Dialog}
 * @api public
 */

exports.dialog = function(title, msg){
  switch (arguments.length) {
    case 2:
      return new Dialog({ title: title, message: msg });
    case 1:
      return new Dialog({ message: title });
  }
};

/**
 * Initialize a new `Dialog`.
 *
 * Options:
 *
 *    - `title` dialog title
 *    - `message` a message to display
 *
 * Emits:
 *
 *    - `show` when visible
 *    - `hide` when hidden
 *
 * @param {Object} options
 * @api public
 */

function Dialog(options) {
  ui.Emitter.call(this);
  options = options || {};
  this.template = html;
  this.el = $(this.template);
  this.render(options);
  if (active && !active.hiding) active.hide();
  if (Dialog.effect) this.effect(Dialog.effect);
  active = this;
};

/**
 * Inherit from `Emitter.prototype`.
 */

Dialog.prototype = new ui.Emitter;

/**
 * Render with the given `options`.
 *
 * @param {Object} options
 * @api public
 */

Dialog.prototype.render = function(options){
  var el = this.el
    , title = options.title
    , msg = options.message
    , self = this;

  el.find('.close').click(function(){
    self.emit('close');
    self.hide();
    return false;
  });

  el.find('h1').text(title);
  if (!title) el.find('h1').remove();

  // message
  if ('string' == typeof msg) {
    el.find('p').text(msg);
  } else if (msg) {
    el.find('p').replaceWith(msg.el || msg);
  }

  setTimeout(function(){
    el.removeClass('hide');
  }, 0);
};

/**
 * Enable the dialog close link.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.closable = function(){
  this.el.addClass('closable');
  return this;
};

/**
 * Set the effect to `type`.
 *
 * @param {String} type
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.effect = function(type){
  this._effect = type;
  this.el.addClass(type);
  return this;
};

/**
 * Make it modal!
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.modal = function(){
  this._overlay = ui.overlay();
  return this;
};

/**
 * Add an overlay.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.overlay = function(){
  var self = this;
  this._overlay = ui
    .overlay({ closable: true })
    .on('hide', function(){
      self.closedOverlay = true;
      self.hide();
    });
  return this;
};

/**
 * Close the dialog when the escape key is pressed.
 *
 * @api private
 */

Dialog.prototype.escapable = function(){
  var self = this;
  $(document).bind('keydown.dialog', function(e){
    if (27 != e.which) return;
    $(this).unbind('keydown.dialog');
    self.hide();
  });
};

/**
 * Show the dialog.
 *
 * Emits "show" event.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.show = function(){
  var overlay = this._overlay;

  this.emit('show');

  if (overlay) {
    overlay.show();
    this.el.addClass('modal');
  }

  // escape
  if (!overlay || overlay.closable) this.escapable();

  this.el.appendTo('body');
  this.el.css({ marginLeft: -(this.el.width() / 2) + 'px' });
  this.emit('show');
  return this;
};

/**
 * Hide the dialog with optional delay of `ms`,
 * otherwise the dialog is removed immediately.
 *
 * Emits "hide" event.
 *
 * @return {Number} ms
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.hide = function(ms){
  var self = this;

  // prevent thrashing
  this.hiding = true;

  // duration
  if (ms) {
    setTimeout(function(){
      self.hide();
    }, ms);
    return this;
  }

  // hide / remove
  this.el.addClass('hide');
  if (this._effect) {
    setTimeout(function(){
      self.remove();
    }, 500);
  } else {
    self.remove();
  }

  // modal
  if (this._overlay && !self.closedOverlay) this._overlay.hide();

  return this;
};

/**
 * Hide the dialog without potential animation.
 *
 * @return {Dialog} for chaining
 * @api public
 */

Dialog.prototype.remove = function(){
  this.emit('hide');
  this.el.remove();
  return this;
};
<|endoftext|>


<commit_before>var gulp = require('gulp'),
	del = require('del'),
	sourcemaps = require('gulp-sourcemaps'),
    browserSync = require('browser-sync'),
	cache = require('gulp-cache'),
    gulpIf = require('gulp-if'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    minifyCSS = require('gulp-minify-css'),
    useref = require('gulp-useref'),
    sass = require('gulp-sass');
	ts = require('gulp-typescript');

gulp.task('style', function() {
  gulp.src('src/scss/*.scss')
      .pipe(sass()).on('error', sass.logError)
      .pipe(gulp.dest('build/css/'))
      .pipe(browserSync.reload({
        stream: true
      }));
});

gulp.task('typescript', function() {
	var project = ts.createProject('tsconfig.json');

	return project.src()
				  .pipe(sourcemaps.init())
				  .pipe(ts(project))
				  .js
				  .pipe(sourcemaps.write())
				  .pipe(gulp.dest('build/js'));
});

gulp.task('fonts', function() {
  return gulp.src('src/fonts/**/*').pipe(gulp.dest('build/css/fonts'))
});

gulp.task('images', function(){
  return gulp.src('src/images/**/*.+(png|jpg|gif|svg)')
  .pipe(cache(imagemin({
    interlaced: true
  })))
  .pipe(gulp.dest('build/images'))
});

gulp.task('browserSync', function() {
  browserSync.init({
    // proxy: "localhost:3000"
    server: {
    	baseDir: "./build"
    }
  })
});

gulp.task('watch', ['typescript', 'browserSync'], function () {
	gulp.watch('src/**/*.ts', ['typescript']);
  	gulp.watch('build/*.html', browserSync.reload);
	gulp.watch('build/js/**/*.js', browserSync.reload);
});

/*
// optimization tasks for dist
gulp.task('useref', ['style'], function() {
  return gulp.src('public/*.html')
             .pipe(useref())
             .pipe(gulpIf('*.js', uglify()))
             .pipe(gulpIf('*.css', minifyCSS()))
             .pipe(gulp.dest('dist'))
});
*/

gulp.task('clean:dist', function(callback){
  del(['dist/**/*', '!dist/images', '!dist/images/**/*'], callback)
});

gulp.task('clean', function(cb) {
	// del('build');
	del('dist');
	return cache.clearAll(cb);
});

gulp.task('default', ['typescript', 'style']);

gulp.task('build', ['useref', 'images', 'fonts'], function() {
  console.log('build done.');
}

gulp.task('dist', ['build'], function() {
  console.log('build dist done.');
}););<commit_msg>add gulp-jspm-build<commit_after>var gulp = require('gulp'),
  	del = require('del'),
  	sourcemaps = require('gulp-sourcemaps'),
    browserSync = require('browser-sync'),
  	cache = require('gulp-cache'),
    gulpIf = require('gulp-if'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    minifyCSS = require('gulp-minify-css'),
    useref = require('gulp-useref'),
    sass = require('gulp-sass'),
    jspm = require('gulp-jspm-build'),
  	ts = require('gulp-typescript');

gulp.task('style', function() {
  gulp.src('src/scss/*.scss')
      .pipe(sass()).on('error', sass.logError)
      .pipe(gulp.dest('build/css/'))
      .pipe(browserSync.reload({
        stream: true
      }));
});

gulp.task('typescript', function() {
	var project = ts.createProject('tsconfig.json');

	return project.src()
				  .pipe(sourcemaps.init())
				  .pipe(ts(project))
				  .js
				  .pipe(sourcemaps.write())
				  .pipe(gulp.dest('build/js'));
});

gulp.task('fonts', function() {
  return gulp.src('src/fonts/**/*').pipe(gulp.dest('build/css/fonts'))
});

gulp.task('images', function(){
  return gulp.src('src/images/**/*.+(png|jpg|gif|svg)')
  .pipe(cache(imagemin({
    interlaced: true
  })))
  .pipe(gulp.dest('build/images'))
});

gulp.task('browserSync', function() {
  browserSync.init({
    // proxy: "localhost:3000"
    server: {
    	baseDir: "./build"
    }
  })
});

gulp.task('watch', ['typescript', 'browserSync'], function () {
	gulp.watch('src/**/*.ts', ['typescript']);
  	gulp.watch('build/*.html', browserSync.reload);
	gulp.watch('build/js/**/*.js', browserSync.reload);
});

/*
// optimization tasks for dist
gulp.task('useref', ['style'], function() {
  return gulp.src('public/*.html')
             .pipe(useref())
             .pipe(gulpIf('*.js', uglify()))
             .pipe(gulpIf('*.css', minifyCSS()))
             .pipe(gulp.dest('dist'))
});
*/

gulp.task('clean:dist', function(callback){
  del(['dist/**/*', '!dist/images', '!dist/images/**/*'], callback)
});

gulp.task('clean', function(cb) {
	// del('build');
	del('dist');
	return cache.clearAll(cb);
});

gulp.task('jspm', function(){
    jspm({
        bundleOptions: {
            minify: true,
            mangle: true
        }
        bundles: [
            { src: 'app', dst: 'app.js' }
            /*
            {
                src: 'react + react-router',
                dst: 'lib.js',
                options: { mangle: false }
            }
            */
        ],
        /*
        configOverride: {
            baseURL: '/foo'
        }
        */
    })
    .pipe(gulp.dest('dist/js'));
});

gulp.task('default', ['typescript', 'style']);

gulp.task('build', ['useref', 'images', 'fonts'], function() {
  console.log('build done.');
}

gulp.task('dist', ['build'], function() {
  console.log('build dist done.');
}););<|endoftext|>


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

import { Link } from 'routes';
import { connect } from 'react-redux';
import { getTools, setFilters } from 'redactions/admin/tools';

import CardApp from 'components/app/common/CardApp';
import Banner from 'components/app/common/Banner';

class Apps extends React.Component {
  static propTypes = {
    tools: PropTypes.object.isRequired,
    getTools: PropTypes.func.isRequired,
    setFilters: PropTypes.func.isRequired
  };

  static defaultProps = {
    tools: {
      list: []
    }
  };

  componentDidMount() {
    this.props.setFilters([]);
    this.props.getTools();
  }

  render() {
    return (

            {this.props.tools.list.map(app => (

                <CardApp
                  background={app.thumbnail.original}
                  title={app.title}
                  description={app.summary}
                  link={{
                    label: 'Go to site',
                    route: app.url,
                    external: true
                  }}
                />

            ))}

                <Banner className="-text-center" bgImage="/static/images/pages/app/bg-banner-planetPulse.jpg">

                    View near-real-time data

                    on the Planet

                  <Link to="pulse">
                    Launch Planet Pulse
                  </Link>
                </Banner>

    );
  }
}

export default connect(
  state => ({
    tools: state.tools
  }),
  { getTools, setFilters }
)(Apps);
<commit_msg>dont use original images<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import { Link } from 'routes';
import { connect } from 'react-redux';
import { getTools, setFilters } from 'redactions/admin/tools';

import CardApp from 'components/app/common/CardApp';
import Banner from 'components/app/common/Banner';

class Apps extends React.Component {
  static propTypes = {
    tools: PropTypes.object.isRequired,
    getTools: PropTypes.func.isRequired,
    setFilters: PropTypes.func.isRequired
  };

  static defaultProps = {
    tools: {
      list: []
    }
  };

  componentDidMount() {
    this.props.setFilters([]);
    this.props.getTools();
  }

  render() {
    return (

            {this.props.tools.list.map(app => (

                <CardApp
                  background={app.thumbnail.medium}
                  title={app.title}
                  description={app.summary}
                  link={{
                    label: 'Go to site',
                    route: app.url,
                    external: true
                  }}
                />

            ))}

                <Banner className="-text-center" bgImage="/static/images/pages/app/bg-banner-planetPulse.jpg">

                    View near-real-time data

                    on the Planet

                  <Link to="pulse">
                    Launch Planet Pulse
                  </Link>
                </Banner>

    );
  }
}

export default connect(
  state => ({
    tools: state.tools
  }),
  { getTools, setFilters }
)(Apps);
<|endoftext|>


<commit_before>function creator(o, data, node) {
	var content = document.createElement(node);
	content.cellspacing = "3"
	var cell = document.createTextNode(data);
	content.appendChild(cell);
	o.appendChild(content);
}

function displayData(arr) {
	var table = document.createElement('table');
	var thead = document.createElement('thead');
	table.appendChild(thead);
	var row = document.createElement('tr');
	creator(row, 'Name', 'th');
	creator(row, 'Type', 'th');
	creator(row, 'Score', 'th');
	thead.appendChild(row);
	var tbody = document.createElement('tbody');
	table.appendChild(tbody);
	for(i=0; i < arr.length; i++){console.log(arr[i]);
		var type = arr[i].type;
		var row = document.createElement('tr');
		creator(row, arr[i]["text"], 'td');
		creator(row, Object.keys(arr[i]["grammar_costs"])[0].slice(0,-1).substring(1), 'td');
		creator(row, arr[i]["grammar_costs"][Object.keys(arr[i]["grammar_costs"])[0]], 'td');
		tbody.appendChild(row);
	}
	document.body.innerHTML = "";
	document.body.appendChild(table);
}

//requireDynamic("Env").user not returning id anymore. So found an alternate
//kept both incase fb reverts back to previous design
id = requireDynamic("Env").user || requireDynamic("CurrentUserInitialData")["id"];
url = "//www.facebook.com/ajax/typeahead/search/facebar/bootstrap/?viewer=" + id + "&__a=1";
x = new XMLHttpRequest();
x.onreadystatechange=function(){
  if (x.readyState==4 && x .status==200){
    srr=JSON.parse(x.responseText.substring(9)).payload.entries;
    displayData(srr);
  }
}
x.open("GET",url,true);
x.send();
<commit_msg>rm logging to console<commit_after>function creator(o, data, node) {
	var content = document.createElement(node);
	content.cellspacing = "3"
	var cell = document.createTextNode(data);
	content.appendChild(cell);
	o.appendChild(content);
}

function displayData(arr) {
	var table = document.createElement('table');
	var thead = document.createElement('thead');
	table.appendChild(thead);
	var row = document.createElement('tr');
	creator(row, 'Name', 'th');
	creator(row, 'Type', 'th');
	creator(row, 'Score', 'th');
	thead.appendChild(row);
	var tbody = document.createElement('tbody');
	table.appendChild(tbody);
	for(i=0; i < arr.length; i++){
		var type = arr[i].type;
		var row = document.createElement('tr');
		creator(row, arr[i]["text"], 'td');
		creator(row, Object.keys(arr[i]["grammar_costs"])[0].slice(0,-1).substring(1), 'td');
		creator(row, arr[i]["grammar_costs"][Object.keys(arr[i]["grammar_costs"])[0]], 'td');
		tbody.appendChild(row);
	}
	document.body.innerHTML = "";
	document.body.appendChild(table);
}

//requireDynamic("Env").user not returning id anymore. So found an alternate
//kept both incase fb reverts back to previous design
id = requireDynamic("Env").user || requireDynamic("CurrentUserInitialData")["id"];
url = "//www.facebook.com/ajax/typeahead/search/facebar/bootstrap/?viewer=" + id + "&__a=1";
x = new XMLHttpRequest();
x.onreadystatechange=function(){
  if (x.readyState==4 && x .status==200){
    srr=JSON.parse(x.responseText.substring(9)).payload.entries;
    displayData(srr);
  }
}
x.open("GET",url,true);
x.send();
<|endoftext|>


<commit_before>'use strict';

const webdriver = require('selenium-webdriver');
const log = require('intel').getLogger('browsertime.command.wait');
const delay = ms => new Promise(res => setTimeout(res, ms));

class Wait {
  constructor(browser, pageCompleteCheck) {
    this.browser = browser;
    this.pageCompleteCheck = pageCompleteCheck;
  }

  /**
   * Wait for an element with id to appear for maxTime.
   * @param {string} id The id to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async byId(id, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.id(id)),
        time
      );
    } catch (e) {
      log.error('Element by id %s was not located in %s ms', id, time);
      log.verbose(e);
      throw Error(`Element by id ${id} was not located in ${time} ms`);
    }
  }

  /**
   * Wait for an element with xpath to appear for maxTime.
   * @param {string} xpath The xpath to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async byXpath(xpath, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.xpath(xpath)),
        time
      );
    } catch (e) {
      log.error('Element by xpath %s was not located in %s ms', xpath, time);
      log.verbose(e);
      throw Error(`Element by xpath ${xpath} was not located in ${time} ms`);
    }
  }

  /**
   * Wait for an element that you find by a selector to appear for maxTime.
   * @param {string} selector The selector to find the element to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async bySelector(selector, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.css(selector)),
        time
      );
    } catch (e) {
      log.error(
        'Element by selector %s was not located in %s ms',
        selector,
        time
      );
      log.verbose(e);
      throw Error(
        `Element by selector ${selector} was not located in ${time} ms`
      );
    }
  }

  /**
   * Wait for x ms.
   * @param {number} ms The tine in ms to wait.
   * @returns {Promise} Promise object represents when the time has timed out.
   */
  async byTime(ms) {
    return delay(ms);
  }

  /**
   * Wait for the page to finish loading.
   * @returns {Promise} Promise object represents when the pageCompleteCheck has finished.
   */
  async byPageToComplete() {
    return this.browser.extraWait(this.pageCompleteCheck);
  }

  /**
   * Wait for an condition that will eventually return a truthy-value for maxTime.
   * @param {string} jsExpression The js code condition to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the condition returned false
   */
  async byCondition(jsExpression, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      const script = `return ${jsExpression}`;
      await driver.wait(() => {
        return driver.executeScript(script);
      }, time);
    } catch (e) {
      log.error('Condition was not met', jsExpression, time);
      log.verbose(e);
      throw Error(`Condition ${jsExpression} was not met in ${time} ms`);
    }
  }
}
module.exports = Wait;
<commit_msg>finetune doc<commit_after>'use strict';

const webdriver = require('selenium-webdriver');
const log = require('intel').getLogger('browsertime.command.wait');
const delay = ms => new Promise(res => setTimeout(res, ms));

class Wait {
  constructor(browser, pageCompleteCheck) {
    this.browser = browser;
    this.pageCompleteCheck = pageCompleteCheck;
  }

  /**
   * Wait for an element with id to appear for maxTime.
   * @param {string} id The id to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async byId(id, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.id(id)),
        time
      );
    } catch (e) {
      log.error('Element by id %s was not located in %s ms', id, time);
      log.verbose(e);
      throw Error(`Element by id ${id} was not located in ${time} ms`);
    }
  }

  /**
   * Wait for an element with xpath to appear for maxTime.
   * @param {string} xpath The xpath to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async byXpath(xpath, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.xpath(xpath)),
        time
      );
    } catch (e) {
      log.error('Element by xpath %s was not located in %s ms', xpath, time);
      log.verbose(e);
      throw Error(`Element by xpath ${xpath} was not located in ${time} ms`);
    }
  }

  /**
   * Wait for an element that you find by a selector to appear for maxTime.
   * @param {string} selector The selector to find the element to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the element is found or the time times out
   * @throws Will throw an error if the element is not found
   */
  async bySelector(selector, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      await driver.wait(
        webdriver.until.elementLocated(webdriver.By.css(selector)),
        time
      );
    } catch (e) {
      log.error(
        'Element by selector %s was not located in %s ms',
        selector,
        time
      );
      log.verbose(e);
      throw Error(
        `Element by selector ${selector} was not located in ${time} ms`
      );
    }
  }

  /**
   * Wait for x ms.
   * @param {number} ms The tine in ms to wait.
   * @returns {Promise} Promise object represents when the time has timed out.
   */
  async byTime(ms) {
    return delay(ms);
  }

  /**
   * Wait for the page to finish loading.
   * @returns {Promise} Promise object represents when the pageCompleteCheck has finished.
   */
  async byPageToComplete() {
    return this.browser.extraWait(this.pageCompleteCheck);
  }

  /**
   * Wait for an condition that will eventually return a truthy-value for maxTime.
   * @param {string} jsExpression The js code condition to wait for
   * @param {number} maxTime Max time to wait in ms
   * @returns {Promise} Promise object represents when the expression becomes truthy or the time times out
   * @throws Will throw an error if the condition returned false
   */
  async byCondition(jsExpression, maxTime) {
    const driver = this.browser.getDriver();
    const time = maxTime || 6000;

    try {
      const script = `return ${jsExpression}`;
      await driver.wait(() => {
        return driver.executeScript(script);
      }, time);
    } catch (e) {
      log.error('Condition was not met', jsExpression, time);
      log.verbose(e);
      throw Error(`Condition ${jsExpression} was not met in ${time} ms`);
    }
  }
}
module.exports = Wait;
<|endoftext|>


<commit_before>// Global vars
var pymChild = null;
var isMobile = false;

/*
 * Initialize graphic
 */
var onWindowLoaded = function () {
    if (Modernizr.svg) {
        formatData();

        pymChild = new pym.Child({
            renderCallback: render,
        });
    } else {
        pymChild = new pym.Child({});
    }
};

/*
 * Format graphic data for processing by D3.
 */
var formatData = function () {
    DATA.forEach(function (d) {
        d.start = +d.start;
        d.end = +d.end;
    });
};

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function (containerWidth) {
    containerWidth = containerWidth || DEFAULT_WIDTH;
    isMobile = (containerWidth <= MOBILE_THRESHOLD);

    // Render the chart!
    renderSlopegraph();

    // Update iframe
    if (pymChild) {
        pymChild.sendHeight();
    }
};

/*
 * Render a line chart.
 */
var renderSlopegraph = function () {
    /*
     * Setup
     */
    var startLabel = LABELS.start_label;
    var endLabel = LABELS.end_label;

    var aspectRatio = getAspectRatio(LABELS.ratio, {
        base: 3 / 2,
        mobile: 2 / 3,
    });

    var margins = {
        top: parseInt(LABELS.marginTop || 20, 10),
        right: parseInt(LABELS.marginRight || 30, 10),
        bottom: parseInt(LABELS.marginBottom || 20, 10),
        left: parseInt(LABELS.marginLeft || 30, 10),
    };

    var labelWidth = parseInt(LABELS.labelWidth || 80, 10);
    var valueGap = parseInt(LABELS.valueGap || 6, 10);

    // Clear existing graphic (for redraw)
    var containerElement = d3.select('#slopegraph');
    containerElement.html('');

    /*
     * Create the root SVG element.
     */
    var chartWrapper = containerElement.append('div')
        .attr('class', 'graphic-wrapper');

    // Calculate actual chart dimensions
    var innerWidth = chartWrapper.node().getBoundingClientRect().width;
    var horizMargins = margins.left + margins.right;
    var vertMargins = margins.top + margins.bottom;
    var labelAndGapWidth = labelWidth + valueGap;
    var noOfLabelCols = isMobile ? 1 : 2;
    var chartWidth = innerWidth - horizMargins - (labelAndGapWidth * noOfLabelCols);
    var chartHeight = Math.ceil(innerWidth / aspectRatio) - vertMargins;

    /*
     * Create D3 scale objects.
     */

    var xLabels = [startLabel, endLabel];

    var xScale = d3.scale.ordinal()
        .domain(xLabels)
        .range([0, chartWidth]);

    var minY = d3.min(DATA, function (d) {
        return Math.min(d.start, d.end);
    });

    var maxY = d3.max(DATA, function (d) {
        return Math.max(d.start, d.end);
    });

    var yScale = d3.scale.linear()
        .domain([minY, maxY])
        .range([chartHeight, 0]);

    var labelScale = d3.scale.ordinal()
        .domain(DATA.map(function (d) {
            return d.label;
        }));

    var colorList = colorArray(LABELS, MONOCHROMECOLORS);
    var colorScale = labelScale.copy()
        .range(colorList);

    var accessibleColorScale = labelScale.copy()
        .range(colorList.map(function (color) {
            return getAccessibleColor(color);
        }));

    var leftOffset = isMobile ? margins.left : margins.left + labelAndGapWidth;

    var chartSVG = chartWrapper.append('svg')
        .attr({
            width: chartWidth + horizMargins + (labelAndGapWidth * noOfLabelCols),
            height: chartHeight + vertMargins,
        });

    var chartElement = chartSVG.append('g')
            .attr('transform', makeTranslate(leftOffset, margins.top));

    /*
     * Render axes to chart.
     */
    chartWrapper.selectAll('svg').append('g')
        .attr('class', 'x axis')
        .selectAll('text')
        .data(xLabels)
        .enter()
        .append('text')
            .style('text-anchor', function (d, i) {
                if (i) {
                    return 'end';
                }
            })
            .attr('x', function (d, i) {
                if (i) {
                    return innerWidth;
                }
            })
            .text(function (d) {
                return d;
            });

    /*
     * Render lines to chart.
     */
    chartElement.append('g')
        .attr('class', 'lines')
        .selectAll('line')
        .data(DATA)
        .enter()
        .append('line')
            .attr('class', function (d, i) {
                return 'line ' + classify(d.label);
            })
            .attr({
                x1: xScale(startLabel),
                y1: function (d) {
                    return yScale(d.start);
                },

                x2: xScale(endLabel),
                y2: function (d) {
                    return yScale(d.end);
                },
            })
            .style('stroke', function (d) {
                return colorScale(d.label);
            });

    /*
     * Uncomment if needed:
     * Move a particular line to the front of the stack
     */

    // svg.select('line.unaffiliated').moveToFront();

    var getGroupedSortedData = function (key) {
        return d3.nest()
            .key(function (d) {
                return d[key];
            })
            .sortKeys(function (a, b) {
                return parseFloat(b) - parseFloat(a);
            })
            .entries(DATA);
    };

    var DATA_GROUPED_START = getGroupedSortedData('start');
    var DATA_GROUPED_END = getGroupedSortedData('end');

    /*
     * Render values.
     */
    var addValues = function (cls) {
        return chartElement.append('g')
            .attr('class', 'value ' + cls)
            .selectAll('text')
            .data(DATA_GROUPED_START)
            .enter()
            .append('text')
                .attr('class', function (d) {
                    return d.values.map(function (v) {
                        return classify(v.label);
                    }).join(' ');
                })
                .attr({
                    x: xScale(cls === 'start' ? startLabel : endLabel),
                    y: function (d) {
                        return yScale(d.values[0][cls]);
                    },

                    dx: (cls === 'start' ? -valueGap : valueGap),
                    dy: 4,
                    fill: function (d) {
                        return accessibleColorScale(d.values[0].label);
                    },
                })
                .text(function (d) {
                    return formattedNumber(
                        d.values[0][cls],
                        LABELS.valuePrefix,
                        LABELS.valueSuffix,
                        LABELS.maxDecimalPlaces
                    );
                });
    };

    var valuesStart = addValues('start');
    var valuesEnd = addValues('end');

    /*
     * Render labels.
     */

    var addLabels = function (elem, d) {
        var g = d3.select(elem);
        d.values.forEach(function (v, i) {
            g.append('text')
                .attr('class', classify(v.label))
                .attr({
                    x: 0,
                    fill: accessibleColorScale(v.label),
                })
                .text(v.label)
                .call(wrapText, labelWidth, '1.1em')
                .attr({
                    y: function () {
                        if (!i) {
                            return 0;
                        }

                        var textElems = g.selectAll('text').filter(function (d, j) {
                            return j < i;
                        });

                        return getCombinedHeightOfElements(textElems);
                    },
                });
        });
    };

    var prevStartYLimit;
    var prevEndYLimit;

    if (!isMobile) {
        // get the width of the widest start value
        var valuesStartMaxWidth = getMaxElemWidth(valuesStart);
        var labelsStart = chartElement.append('g')
            .attr('class', 'label start')
            .selectAll('g')
            .data(DATA_GROUPED_START)
            .enter()
            .append('g')
                .each(function (d) {
                    addLabels(this, d);
                })
                .attr('transform', function (d, i) {
                    var x = xScale(startLabel) - (valuesStartMaxWidth + (valueGap * 2));
                    var y = yScale(d.values[0].start) + 4;

                    if (i) {
                        if (y < prevStartYLimit) {
                            y = prevStartYLimit;

                            valuesStart.filter(function (e, j) {
                                return i === j;
                            }).attr({
                                y: prevStartYLimit - 4,
                            });
                        }

                    }

                    // set prev value for the next item
                    var textElems = d3.select(this).selectAll('text');
                    prevStartYLimit = y + getCombinedHeightOfElements(textElems);

                    return makeTranslate(x, y);
                });
    } else {
        // Need to reposition values so they don't overlap
        // (on mobile they don't have the labels)
        valuesStart.each(function (d, i) {
            var selection = d3.select(this);
            var y = parseFloat(selection.attr('y'), 10);

            if (i) {
                if (y < prevYLimit) {
                    y = prevYLimit;
                    selection.attr({
                        y: prevYLimit,
                    });
                }
            }

            // set prev value for the next item
            prevStartYLimit = y + this.clientHeight;
        });

    }

    // get the width of the widest end value
    var valuesEndMaxWidth = getMaxElemWidth(valuesEnd);
    var labelsEnd = chartElement.append('g')
        .attr('class', 'label end')
        .selectAll('g')
        .data(DATA_GROUPED_END)
        .enter()
        .append('g')
            .each(function (d) {
                addLabels(this, d);
            })
            .attr('transform', function (d, i) {
                var x = xScale(endLabel) + valuesEndMaxWidth + (valueGap * 2);
                var y = yScale(d.values[0].end) + 4;

                if (i) {
                    if (y < prevEndYLimit) {
                        y = prevEndYLimit;

                        // move the value down too
                        valuesEnd.filter(function (e, j) {
                            return i === j;
                        }).attr({
                            y: prevEndYLimit - 4,
                        });
                    }

                }

                // set prev value for the next item
                var textElems = d3.select(this).selectAll('text');
                prevEndYLimit = y + getCombinedHeightOfElements(textElems);

                return makeTranslate(x, y);
            });

    // increase height to accommodate multiline labels
    chartSVG.attr('height', d3.max([prevStartYLimit, prevEndYLimit]) + vertMargins);

    chartElement.selectAll('.value, .label, .lines')
        .attr('transform', 'translate(0,15)');

};

var getMaxElemWidth = function (elems) {
    var maxWidth = 0;
    elems.each(function () {
        var width = d3.select(this).node().getComputedTextLength();
        if (width > maxWidth) {
            maxWidth = width;
        }
    });

    return maxWidth;
};

var getCombinedHeightOfElements = function (selection) {
    var height = 0;
    selection.each(function (t, j) {
        height = height + this.clientHeight;
    });

    return height;
};

/*
 * Wrap a block of text to a given width
 * via http://bl.ocks.org/mbostock/7555321
 */
var wrapText = function (texts, width, lineHeight) {
    texts.each(function () {
        var text = d3.select(this);
        var words = text.text().split(/\s+/).reverse();

        var word = null;
        var line = [];
        var lineNumber = 0;

        var x = text.attr('x');
        var y = text.attr('y');

        var dx = parseFloat(text.attr('dx') || 0);
        var dy = parseFloat(text.attr('dy') || 0);

        var tspan = text.text(null)
            .append('tspan')
            .attr({
                x: x,
                dx: dx,
                dy: dy,
            });

        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(' '));

            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(' '));
                line = [word];

                lineNumber += 1;

                tspan = text.append('tspan')
                    .attr({
                        x: x,
                        dx: dx,
                        dy: lineNumber ? lineHeight : 0,
                    })
                    .text(word);
            }
        }
    });
};

/*
 * Select an element and move it to the front of the stack
 */
d3.selection.prototype.moveToFront = function () {
    return this.each(function () {
        this.parentNode.appendChild(this);
    });
};

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<commit_msg>Fix layout issues on slope graph<commit_after>// Global vars
var pymChild = null;
var isMobile = false;

/*
 * Initialize graphic
 */
var onWindowLoaded = function () {
    if (Modernizr.svg) {
        formatData();

        pymChild = new pym.Child({
            renderCallback: render,
        });
    } else {
        pymChild = new pym.Child({});
    }
};

/*
 * Format graphic data for processing by D3.
 */
var formatData = function () {
    DATA.forEach(function (d) {
        d.start = +d.start;
        d.end = +d.end;
    });
};

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function (containerWidth) {
    containerWidth = containerWidth || DEFAULT_WIDTH;
    isMobile = (containerWidth <= MOBILE_THRESHOLD);

    // Render the chart!
    renderSlopegraph();

    // Update iframe
    if (pymChild) {
        pymChild.sendHeight();
    }
};

/*
 * Render a line chart.
 */
var renderSlopegraph = function () {
    /*
     * Setup
     */
    var startLabel = LABELS.start_label;
    var endLabel = LABELS.end_label;

    var aspectRatio = getAspectRatio(LABELS.ratio, {
        base: 3 / 2,
        mobile: 2 / 3,
    });

    var margins = {
        top: parseInt(LABELS.marginTop || 20, 10),
        right: parseInt(LABELS.marginRight || 30, 10),
        bottom: parseInt(LABELS.marginBottom || 20, 10),
        left: parseInt(LABELS.marginLeft || 30, 10),
    };

    var labelWidth = parseInt(LABELS.labelWidth || 80, 10);
    var valueGap = parseInt(LABELS.valueGap || 6, 10);

    // Clear existing graphic (for redraw)
    var containerElement = d3.select('#slopegraph');
    containerElement.html('');

    /*
     * Create the root SVG element.
     */
    var chartWrapper = containerElement.append('div')
        .attr('class', 'graphic-wrapper');

    // Calculate actual chart dimensions
    var innerWidth = chartWrapper.node().getBoundingClientRect().width;
    var horizMargins = margins.left + margins.right;
    var vertMargins = margins.top + margins.bottom;
    var labelAndGapWidth = labelWidth + valueGap;
    var noOfLabelCols = isMobile ? 1 : 2;
    var chartWidth = innerWidth - horizMargins - (labelAndGapWidth * noOfLabelCols);
    var chartHeight = Math.ceil(innerWidth / aspectRatio) - vertMargins;

    /*
     * Create D3 scale objects.
     */

    var xLabels = [startLabel, endLabel];

    var xScale = d3.scale.ordinal()
        .domain(xLabels)
        .range([0, chartWidth]);

    var minY = d3.min(DATA, function (d) {
        return Math.min(d.start, d.end);
    });

    var maxY = d3.max(DATA, function (d) {
        return Math.max(d.start, d.end);
    });

    var yScale = d3.scale.linear()
        .domain([minY, maxY])
        .range([chartHeight, 0]);

    var labelScale = d3.scale.ordinal()
        .domain(DATA.map(function (d) {
            return d.label;
        }));

    var colorList = colorArray(LABELS, MONOCHROMECOLORS);
    var colorScale = labelScale.copy()
        .range(colorList);

    var accessibleColorScale = labelScale.copy()
        .range(colorList.map(function (color) {
            return getAccessibleColor(color);
        }));

    var leftOffset = isMobile ? margins.left : margins.left + labelAndGapWidth;

    var chartSVG = chartWrapper.append('svg')
        .attr({
            width: chartWidth + horizMargins + (labelAndGapWidth * noOfLabelCols),
            height: chartHeight + vertMargins,
        });

    var chartElement = chartSVG.append('g')
            .attr('transform', makeTranslate(leftOffset, margins.top));

    /*
     * Render axes to chart.
     */
    chartWrapper.selectAll('svg').append('g')
        .attr('class', 'x axis')
        .selectAll('text')
        .data(xLabels)
        .enter()
        .append('text')
            .style('text-anchor', function (d, i) {
                if (i) {
                    return 'end';
                }
            })
            .attr('x', function (d, i) {
                if (i) {
                    return innerWidth;
                }
            })
            .text(function (d) {
                return d;
            });

    /*
     * Render lines to chart.
     */
    chartElement.append('g')
        .attr('class', 'lines')
        .selectAll('line')
        .data(DATA)
        .enter()
        .append('line')
            .attr('class', function (d, i) {
                return 'line ' + classify(d.label);
            })
            .attr({
                x1: xScale(startLabel),
                y1: function (d) {
                    return yScale(d.start);
                },

                x2: xScale(endLabel),
                y2: function (d) {
                    return yScale(d.end);
                },
            })
            .style('stroke', function (d) {
                return colorScale(d.label);
            });

    /*
     * Uncomment if needed:
     * Move a particular line to the front of the stack
     */

    // svg.select('line.unaffiliated').moveToFront();

    var getGroupedSortedData = function (key) {
        return d3.nest()
            .key(function (d) {
                return d[key];
            })
            .sortKeys(function (a, b) {
                return parseFloat(b) - parseFloat(a);
            })
            .entries(DATA);
    };

    var DATA_GROUPED_START = getGroupedSortedData('start');
    var DATA_GROUPED_END = getGroupedSortedData('end');

    /*
     * Render values.
     */
    var addValues = function (cls) {
        return chartElement.append('g')
            .attr('class', 'value ' + cls)
            .selectAll('text')
            .data((cls === 'start') ? DATA_GROUPED_START : DATA_GROUPED_END)
            .enter()
            .append('text')
                .attr('class', function (d) {
                    return d.values.map(function (v) {
                        return classify(v.label);
                    }).join(' ');
                })
                .attr({
                    x: xScale(cls === 'start' ? startLabel : endLabel),
                    y: function (d) {
                        return yScale(d.values[0][cls]);
                    },

                    dx: (cls === 'start' ? -valueGap : valueGap),
                    dy: 4,
                    fill: function (d) {
                        return accessibleColorScale(d.values[0].label);
                    },
                })
                .text(function (d) {
                    return formattedNumber(
                        d.values[0][cls],
                        LABELS.valuePrefix,
                        LABELS.valueSuffix,
                        LABELS.maxDecimalPlaces
                    );
                });
    };

    var valuesStart = addValues('start');
    var valuesEnd = addValues('end');

    /*
     * Render labels.
     */

    var addLabels = function (elem, d) {
        var g = d3.select(elem);
        d.values.forEach(function (v, i) {
            g.append('text')
                .attr('class', classify(v.label))
                .attr({
                    x: 0,
                    fill: accessibleColorScale(v.label),
                })
                .text(v.label)
                .call(wrapText, labelWidth, '1.1em')
                .attr({
                    y: function () {
                        if (!i) {
                            return 0;
                        }

                        var textElems = g.selectAll('text').filter(function (d, j) {
                            return j < i;
                        });

                        return getCombinedHeightOfElements(textElems);
                    },
                });
        });
    };

    var prevStartYLimit;
    var prevEndYLimit;

    if (!isMobile) {
        // get the width of the widest start value
        var valuesStartMaxWidth = getMaxElemWidth(valuesStart);
        var labelsStart = chartElement.append('g')
            .attr('class', 'label start')
            .selectAll('g')
            .data(DATA_GROUPED_START)
            .enter()
            .append('g')
                .each(function (d) {
                    addLabels(this, d);
                })
                .attr('transform', function (d, i) {
                    var x = xScale(startLabel) - (valuesStartMaxWidth + (valueGap * 2));
                    var y = yScale(d.values[0].start) + 4;

                    if (i) {
                        if (y < prevStartYLimit) {
                            y = prevStartYLimit;

                            valuesStart.filter(function (e, j) {
                                return i === j;
                            }).attr({
                                y: prevStartYLimit - 4,
                            });
                        }

                    }

                    // set prev value for the next item
                    var textElems = d3.select(this).selectAll('text');
                    prevStartYLimit = y + getCombinedHeightOfElements(textElems);

                    return makeTranslate(x, y);
                });
    } else {
        // Need to reposition values so they don't overlap
        // (on mobile they don't have the labels)
        valuesStart.each(function (d, i) {

            var selection = d3.select(this);
            var y = parseFloat(selection.attr('y'), 10);

            if (i) {
                if (y < prevStartYLimit) {
                    y = prevStartYLimit;
                    selection.attr({
                        y: prevStartYLimit,
                    });
                }
            }

            // set prev value for the next item
            prevStartYLimit = y + this.getBBox().height;
        });

    }

    // get the width of the widest end value
    var valuesEndMaxWidth = getMaxElemWidth(valuesEnd);
    var labelsEnd = chartElement.append('g')
        .attr('class', 'label end')
        .selectAll('g')
        .data(DATA_GROUPED_END)
        .enter()
        .append('g')
            .each(function (d) {
                addLabels(this, d);
            })
            .attr('transform', function (d, i) {
                var x = xScale(endLabel) + valuesEndMaxWidth + (valueGap * 2);
                var y = yScale(d.values[0].end) + 4;

                if (i) {
                    if (y < prevEndYLimit) {
                        y = prevEndYLimit;

                        // move the value down too
                        valuesEnd.filter(function (e, j) {
                            return i === j;
                        }).attr({
                            y: prevEndYLimit - 4,
                        });
                    }

                }

                // set prev value for the next item
                var textElems = d3.select(this).selectAll('text');
                prevEndYLimit = y + getCombinedHeightOfElements(textElems);

                return makeTranslate(x, y);
            });

    // increase height to accommodate multiline labels
    chartSVG.attr('height', d3.max([prevStartYLimit, prevEndYLimit]) + vertMargins);

    chartElement.selectAll('.value, .label, .lines')
        .attr('transform', 'translate(0,15)');

};

var getMaxElemWidth = function (elems) {
    var maxWidth = 0;
    elems.each(function () {
        var width = d3.select(this).node().getComputedTextLength();
        if (width > maxWidth) {
            maxWidth = width;
        }
    });

    return maxWidth;
};

var getCombinedHeightOfElements = function (selection) {
    var height = 0;
    selection.each(function (t, j) {
        height = height + this.getBBox().height;
    });

    return height;
};

/*
 * Wrap a block of text to a given width
 * via http://bl.ocks.org/mbostock/7555321
 */
var wrapText = function (texts, width, lineHeight) {
    texts.each(function () {
        var text = d3.select(this);
        var words = text.text().split(/\s+/).reverse();

        var word = null;
        var line = [];
        var lineNumber = 0;

        var x = text.attr('x');
        var y = text.attr('y');

        var dx = parseFloat(text.attr('dx') || 0);
        var dy = parseFloat(text.attr('dy') || 0);

        var tspan = text.text(null)
            .append('tspan')
            .attr({
                x: x,
                dx: dx,
                dy: dy,
            });

        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(' '));

            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(' '));
                line = [word];

                lineNumber += 1;

                tspan = text.append('tspan')
                    .attr({
                        x: x,
                        dx: dx,
                        dy: lineNumber ? lineHeight : 0,
                    })
                    .text(word);
            }
        }
    });
};

/*
 * Select an element and move it to the front of the stack
 */
d3.selection.prototype.moveToFront = function () {
    return this.each(function () {
        this.parentNode.appendChild(this);
    });
};

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<|endoftext|>


<commit_before>Ext.require([
  'Ext.container.Container',
  'Cs.file.data.FileUploader',
  'Cs.file.ui.FileItem'
]);

Ext.define('Cs.file.ui.UglyFileUploader', {
  extend: 'Ext.container.Container',
  alias: 'widget.uglyfileuploader',
  config: {
    mgr: null
  },
  constructor: function(config) {
    var listContainer,
    me = this,
    fileItems = { },
    form,
    fileMgr = config["mgr"] || null,
    uploader = Ext.create('Cs.file.data.FileUploader', fileMgr, {
      url: "upload.php",
      progress: function(file, total, amt, evt) {
        console.log("Uploaded " + Ext.Number.toFixed(100 * amt / total, 2) + " of " + file.get('name'));
      },
      success: function(file, response, options) {
        console.log("Successfully uploaded " + file.get('name'));
      },
      failure: function(file, response, options) {
        console.log("Failed to upload " + file.get('name'));
      },
      callback: function(file, options, success, response) {
        console.log("Callback for " + file.get('name'));
      }});

    this.initConfig(config);

    fileMgr.on('fileadded', function(record) {
      var item = Ext.create('Cs.file.ui.FileItem', record.get('name'), record.get('size'));

      item.on('remove', function () {
        fileMgr.removeFile(record);
        listContainer.remove(item);
      });

      listContainer.add(item);
    }, this);

    this.privateInit = function() {
      var count = 1;

      me.insert(0, {
        xtype: 'button',
        height: 20,
        text: 'Upload Files',
        listeners: {
          click: function() {
            uploader.upload();
          }
        }
      });

      listContainer = me.insert(0, {
        xtype: "container",
        width: "100%",
        flex: 1,
        autoScroll: true,
        layout: {type: "vbox", align: "stretch"}
      });

      form = me.insert(0, {
        xtype: "container",
        width: "100%",
        layout: {type: "hbox", pack: "end"},
        items: [{
          xtype: "filefield",
          name: "filepicker",
          width: 80,
          buttonText: "Add a File ... (" + count + ")",
          buttonOnly: true,
          multiple: true,
          listeners: {
            change: function(field, value, opt) {
              var inputCnt = field.ownerCt,
              inputEl = field.fileInputEl;

              if(inputEl.dom.files) {
                Ext.Array.each(inputEl.dom.files, fileMgr.addFile, fileMgr);
              }
              else if(inputEl.getValue()) {
                fileMgr.addFile(field);

                count = count + 1;

                inputCnt.add(field.cloneConfig({buttonText: "Add a File ... (" + count + ")"}));
                field.setVisible(false);
              }
              else
                throw "Unsupported file input type.";
            }
          }
        }]
      });

      me.on("afterrender", function () {
        var myEl = me.getEl();

        // necessary to prevent browser redirect when the file is
        // dropped.
        myEl.dom.addEventListener("dragover", function (evt) {
          evt.stopPropagation();
          evt.preventDefault();

          return false;
        }, false);

        myEl.dom.addEventListener("drop", function (evt) {

          evt.stopPropagation();
          evt.preventDefault();

          Ext.Array.each(evt.dataTransfer.files, function(file) {
            fileMgr.addFile(file);
          });

        }, false);
      }, me);
    };

    this.callParent([config]);
  },
  initComponent: function() {
    this.callParent();
    this.privateInit();
  }
});

<commit_msg>Check that console exists before using it.<commit_after>Ext.require([
  'Ext.container.Container',
  'Cs.file.data.FileUploader',
  'Cs.file.ui.FileItem'
]);

Ext.define('Cs.file.ui.UglyFileUploader', {
  extend: 'Ext.container.Container',
  alias: 'widget.uglyfileuploader',
  config: {
    mgr: null
  },
  constructor: function(config) {
    var listContainer,
    me = this,
    fileItems = { },
    form,
    fileMgr = config["mgr"] || null,
    uploader = Ext.create('Cs.file.data.FileUploader', fileMgr, {
      url: "upload.php",
      progress: function(file, total, amt, evt) {
        if(window['console'])
          console.log("Uploaded " + Ext.Number.toFixed(100 * amt / total, 2) + " of " + file.get('name'));
      },
      success: function(file, response, options) {
        if(window['console'])
          console.log("Successfully uploaded " + file.get('name'));
      },
      failure: function(file, response, options) {
        if(window['console'])
          console.log("Failed to upload " + file.get('name'));
      },
      callback: function(file, options, success, response) {
        if(window['console'])
          console.log("Callback for " + file.get('name'));
      }});

    this.initConfig(config);

    fileMgr.on('fileadded', function(record) {
      var item = Ext.create('Cs.file.ui.FileItem', record.get('name'), record.get('size'));

      item.on('remove', function () {
        fileMgr.removeFile(record);
        listContainer.remove(item);
      });

      listContainer.add(item);
    }, this);

    this.privateInit = function() {
      var count = 1;

      me.insert(0, {
        xtype: 'button',
        height: 20,
        text: 'Upload Files',
        listeners: {
          click: function() {
            uploader.upload();
          }
        }
      });

      listContainer = me.insert(0, {
        xtype: "container",
        width: "100%",
        flex: 1,
        autoScroll: true,
        layout: {type: "vbox", align: "stretch"}
      });

      form = me.insert(0, {
        xtype: "container",
        width: "100%",
        layout: {type: "hbox", pack: "end"},
        items: [{
          xtype: "filefield",
          name: "filepicker",
          width: 80,
          buttonText: "Add a File ... (" + count + ")",
          buttonOnly: true,
          multiple: true,
          listeners: {
            change: function(field, value, opt) {
              var inputCnt = field.ownerCt,
              inputEl = field.fileInputEl;

              if(inputEl.dom.files) {
                Ext.Array.each(inputEl.dom.files, fileMgr.addFile, fileMgr);
              }
              else if(inputEl.getValue()) {
                fileMgr.addFile(field);

                count = count + 1;

                inputCnt.add(field.cloneConfig({buttonText: "Add a File ... (" + count + ")"}));
                field.setVisible(false);
              }
              else
                throw "Unsupported file input type.";
            }
          }
        }]
      });

      me.on("afterrender", function () {
        var myEl = me.getEl();

        // necessary to prevent browser redirect when the file is
        // dropped.
        myEl.dom.addEventListener("dragover", function (evt) {
          evt.stopPropagation();
          evt.preventDefault();

          return false;
        }, false);

        myEl.dom.addEventListener("drop", function (evt) {

          evt.stopPropagation();
          evt.preventDefault();

          Ext.Array.each(evt.dataTransfer.files, function(file) {
            fileMgr.addFile(file);
          });

        }, false);
      }, me);
    };

    this.callParent([config]);
  },
  initComponent: function() {
    this.callParent();
    this.privateInit();
  }
});

<|endoftext|>


<commit_before>const createStandardErrorMessage = require('./createStandardErrorMessage');
const makePromise = require('./makePromise');
const addAdditionalPromiseMethods = require('./addAdditionalPromiseMethods');
const wrapPromiseIfNecessary = require('./wrapPromiseIfNecessary');
const oathbreaker = require('./oathbreaker');
const UnexpectedError = require('./UnexpectedError');
const utils = require('./utils');

function isAssertionArg({ type }) {
  return type.is('assertion');
}

function lookupAssertionsInParentChain(assertionString, unexpected) {
  const assertions = [];
  for (let instance = unexpected; instance; instance = instance.parent) {
    if (instance.assertions[assertionString]) {
      assertions.push(...instance.assertions[assertionString]);
    }
  }
  return assertions;
}

function findSuffixAssertions(assertionString, unexpected) {
  if (typeof assertionString !== 'string') {
    return null;
  }
  const straightforwardAssertions = lookupAssertionsInParentChain(
    assertionString,
    unexpected
  );
  if (straightforwardAssertions.length > 0) {
    return straightforwardAssertions;
  }
  const tokens = assertionString.split(' ');
  for (let n = tokens.length - 1; n > 0; n -= 1) {
    const suffix = tokens.slice(n).join(' ');
    const suffixAssertions = lookupAssertionsInParentChain(suffix, unexpected);
    if (
      findSuffixAssertions(tokens.slice(0, n).join(' '), unexpected) &&
      suffixAssertions.length > 0
    ) {
      return suffixAssertions;
    }
  }
  return null;
}

module.exports = function createWrappedExpectProto(unexpected) {
  const wrappedExpectProto = {
    promise: makePromise,
    errorMode: 'default',

    equal: unexpected.equal,
    inspect: unexpected.inspect,
    createOutput: unexpected.createOutput.bind(unexpected),
    findTypeOf: unexpected.findTypeOf.bind(unexpected),
    findTypeOfWithParentType: unexpected.findTypeOfWithParentType.bind(
      unexpected
    ),
    findCommonType: unexpected.findCommonType.bind(unexpected),
    it(...args) {
      if (typeof args[0] === 'string') {
        args[0] = utils.forwardFlags(args[0], this.flags);
      }
      return unexpected.it(...args);
    },
    diff: unexpected.diff,
    getType: unexpected.getType.bind(unexpected),
    output: unexpected.output,
    outputFormat: unexpected.outputFormat.bind(unexpected),
    format: unexpected.format,
    withError: unexpected.withError,

    fail(...args) {
      const expect = this.context.expect;
      this.callInNestedContext(() => {
        expect.fail(...args);
      });
    },
    standardErrorMessage(output, options) {
      const that = this;
      options = typeof options === 'object' ? options : {};

      if ('omitSubject' in output) {
        options.subject = this.subject;
      }

      if (options && options.compact) {
        options.compactSubject = output => {
          output.jsFunctionName(that.subjectType.name);
        };
      }
      return createStandardErrorMessage(
        output,
        that.subjectOutput,
        that.testDescription,
        that.argsOutput,
        options
      );
    },
    callInNestedContext(callback) {
      const that = this;

      try {
        let result = oathbreaker(callback());
        if (utils.isPromise(result)) {
          result = wrapPromiseIfNecessary(result);
          if (result.isPending()) {
            result = result.then(undefined, e => {
              if (e && e._isUnexpected) {
                const wrappedError = new UnexpectedError(that, e);
                wrappedError.originalError = e.originalError;
                throw wrappedError;
              }
              throw e;
            });
          }
        } else {
          result = makePromise.resolve(result);
        }
        return addAdditionalPromiseMethods(result, that.execute, that.subject);
      } catch (e) {
        if (e && e._isUnexpected) {
          const wrappedError = new UnexpectedError(that, e);
          wrappedError.originalError = e.originalError;
          throw wrappedError;
        }
        throw e;
      }
    },
    shift(subject, assertionIndex) {
      if (arguments.length <= 1) {
        if (arguments.length === 0) {
          subject = this.subject;
        }
        assertionIndex = -1;
        for (let i = 0; i < this.assertionRule.args.length; i += 1) {
          const type = this.assertionRule.args[i].type;
          if (type.is('assertion') || type.is('expect.it')) {
            assertionIndex = i;
            break;
          }
        }
      } else if (arguments.length === 3) {
        // The 3-argument syntax for wrappedExpect.shift is deprecated, please omit the first (expect) arg
        subject = arguments[1];
        assertionIndex = arguments[2];
      }

      if (assertionIndex !== -1) {
        const args = this.args.slice(0, assertionIndex);
        const rest = this.args.slice(assertionIndex);
        const nextArgumentType = this.findTypeOf(rest[0]);
        if (arguments.length > 1) {
          // Legacy
          this.argsOutput = output => {
            args.forEach((arg, index) => {
              if (index > 0) {
                output.text(', ');
              }
              output.appendInspected(arg);
            });

            if (args.length > 0) {
              output.sp();
            }
            if (nextArgumentType.is('string')) {
              output.error(rest[0]);
            } else if (rest.length > 0) {
              output.appendInspected(rest[0]);
            }
            if (rest.length > 1) {
              output.sp();
            }
            rest.slice(1).forEach((arg, index) => {
              if (index > 0) {
                output.text(', ');
              }
              output.appendInspected(arg);
            });
          };
        }
        if (nextArgumentType.is('expect.it')) {
          const that = this;
          return this.withError(
            () => rest[0](subject),
            err => {
              that.fail(err);
            }
          );
        } else if (nextArgumentType.is('string')) {
          return this.execute(subject, ...rest);
        } else {
          return subject;
        }
      } else {
        // No assertion to delegate to. Provide the new subject as the fulfillment value:
        return subject;
      }
    },
    _getSubjectType() {
      return this.findTypeOfWithParentType(
        this.subject,
        this.assertionRule.subject.type
      );
    },
    _getArgTypes(index) {
      const lastIndex = this.assertionRule.args.length - 1;
      return this.args.map(function(arg, index) {
        return this.findTypeOfWithParentType(
          arg,
          this.assertionRule.args[Math.min(index, lastIndex)].type
        );
      }, this);
    },
    _getAssertionIndices() {
      if (!this._assertionIndices) {
        const assertionIndices = [];
        const args = this.args;
        let currentAssertionRule = this.assertionRule;
        let offset = 0;
        // eslint-disable-next-line no-labels
        OUTER: while (true) {
          if (
            currentAssertionRule.args.length > 1 &&
            isAssertionArg(
              currentAssertionRule.args[currentAssertionRule.args.length - 2]
            )
          ) {
            assertionIndices.push(
              offset + currentAssertionRule.args.length - 2
            );
            const suffixAssertions = findSuffixAssertions(
              args[offset + currentAssertionRule.args.length - 2],
              unexpected
            );
            if (suffixAssertions) {
              for (let i = 0; i < suffixAssertions.length; i += 1) {
                if (suffixAssertions[i].args.some(isAssertionArg)) {
                  offset += currentAssertionRule.args.length - 1;
                  currentAssertionRule = suffixAssertions[i];
                  // eslint-disable-next-line no-labels
                  continue OUTER;
                }
              }
            }
          }
          // No further assertions found,
          break;
        }
        this._assertionIndices = assertionIndices;
      }
      return this._assertionIndices;
    }
  };

  if (Object.__defineGetter__) {
    Object.defineProperty(wrappedExpectProto, 'subjectType', {
      enumerable: true,
      get() {
        return this.assertionRule && this._getSubjectType();
      }
    });

    Object.defineProperty(wrappedExpectProto, 'argTypes', {
      enumerable: true,
      get() {
        return this.assertionRule && this._getArgTypes();
      }
    });
  }

  utils.setPrototypeOfOrExtend(wrappedExpectProto, Function.prototype);
  return wrappedExpectProto;
};
<commit_msg>unexpected => expect<commit_after>const createStandardErrorMessage = require('./createStandardErrorMessage');
const makePromise = require('./makePromise');
const addAdditionalPromiseMethods = require('./addAdditionalPromiseMethods');
const wrapPromiseIfNecessary = require('./wrapPromiseIfNecessary');
const oathbreaker = require('./oathbreaker');
const UnexpectedError = require('./UnexpectedError');
const utils = require('./utils');

function isAssertionArg({ type }) {
  return type.is('assertion');
}

function lookupAssertionsInParentChain(assertionString, expect) {
  const assertions = [];
  for (let instance = expect; instance; instance = instance.parent) {
    if (instance.assertions[assertionString]) {
      assertions.push(...instance.assertions[assertionString]);
    }
  }
  return assertions;
}

function findSuffixAssertions(assertionString, expect) {
  if (typeof assertionString !== 'string') {
    return null;
  }
  const straightforwardAssertions = lookupAssertionsInParentChain(
    assertionString,
    expect
  );
  if (straightforwardAssertions.length > 0) {
    return straightforwardAssertions;
  }
  const tokens = assertionString.split(' ');
  for (let n = tokens.length - 1; n > 0; n -= 1) {
    const suffix = tokens.slice(n).join(' ');
    const suffixAssertions = lookupAssertionsInParentChain(suffix, expect);
    if (
      findSuffixAssertions(tokens.slice(0, n).join(' '), expect) &&
      suffixAssertions.length > 0
    ) {
      return suffixAssertions;
    }
  }
  return null;
}

module.exports = function createWrappedExpectProto(expect) {
  const wrappedExpectProto = {
    promise: makePromise,
    errorMode: 'default',

    equal: expect.equal,
    inspect: expect.inspect,
    createOutput: expect.createOutput.bind(expect),
    findTypeOf: expect.findTypeOf.bind(expect),
    findTypeOfWithParentType: expect.findTypeOfWithParentType.bind(expect),
    findCommonType: expect.findCommonType.bind(expect),
    it(...args) {
      if (typeof args[0] === 'string') {
        args[0] = utils.forwardFlags(args[0], this.flags);
      }
      return expect.it(...args);
    },
    diff: expect.diff,
    getType: expect.getType.bind(expect),
    output: expect.output,
    outputFormat: expect.outputFormat.bind(expect),
    format: expect.format,
    withError: expect.withError,

    fail(...args) {
      const expect = this.context.expect;
      this.callInNestedContext(() => {
        expect.fail(...args);
      });
    },
    standardErrorMessage(output, options) {
      const that = this;
      options = typeof options === 'object' ? options : {};

      if ('omitSubject' in output) {
        options.subject = this.subject;
      }

      if (options && options.compact) {
        options.compactSubject = output => {
          output.jsFunctionName(that.subjectType.name);
        };
      }
      return createStandardErrorMessage(
        output,
        that.subjectOutput,
        that.testDescription,
        that.argsOutput,
        options
      );
    },
    callInNestedContext(callback) {
      const that = this;

      try {
        let result = oathbreaker(callback());
        if (utils.isPromise(result)) {
          result = wrapPromiseIfNecessary(result);
          if (result.isPending()) {
            result = result.then(undefined, e => {
              if (e && e._isUnexpected) {
                const wrappedError = new UnexpectedError(that, e);
                wrappedError.originalError = e.originalError;
                throw wrappedError;
              }
              throw e;
            });
          }
        } else {
          result = makePromise.resolve(result);
        }
        return addAdditionalPromiseMethods(result, that.execute, that.subject);
      } catch (e) {
        if (e && e._isUnexpected) {
          const wrappedError = new UnexpectedError(that, e);
          wrappedError.originalError = e.originalError;
          throw wrappedError;
        }
        throw e;
      }
    },
    shift(subject, assertionIndex) {
      if (arguments.length <= 1) {
        if (arguments.length === 0) {
          subject = this.subject;
        }
        assertionIndex = -1;
        for (let i = 0; i < this.assertionRule.args.length; i += 1) {
          const type = this.assertionRule.args[i].type;
          if (type.is('assertion') || type.is('expect.it')) {
            assertionIndex = i;
            break;
          }
        }
      } else if (arguments.length === 3) {
        // The 3-argument syntax for wrappedExpect.shift is deprecated, please omit the first (expect) arg
        subject = arguments[1];
        assertionIndex = arguments[2];
      }

      if (assertionIndex !== -1) {
        const args = this.args.slice(0, assertionIndex);
        const rest = this.args.slice(assertionIndex);
        const nextArgumentType = this.findTypeOf(rest[0]);
        if (arguments.length > 1) {
          // Legacy
          this.argsOutput = output => {
            args.forEach((arg, index) => {
              if (index > 0) {
                output.text(', ');
              }
              output.appendInspected(arg);
            });

            if (args.length > 0) {
              output.sp();
            }
            if (nextArgumentType.is('string')) {
              output.error(rest[0]);
            } else if (rest.length > 0) {
              output.appendInspected(rest[0]);
            }
            if (rest.length > 1) {
              output.sp();
            }
            rest.slice(1).forEach((arg, index) => {
              if (index > 0) {
                output.text(', ');
              }
              output.appendInspected(arg);
            });
          };
        }
        if (nextArgumentType.is('expect.it')) {
          const that = this;
          return this.withError(
            () => rest[0](subject),
            err => {
              that.fail(err);
            }
          );
        } else if (nextArgumentType.is('string')) {
          return this.execute(subject, ...rest);
        } else {
          return subject;
        }
      } else {
        // No assertion to delegate to. Provide the new subject as the fulfillment value:
        return subject;
      }
    },
    _getSubjectType() {
      return this.findTypeOfWithParentType(
        this.subject,
        this.assertionRule.subject.type
      );
    },
    _getArgTypes(index) {
      const lastIndex = this.assertionRule.args.length - 1;
      return this.args.map(function(arg, index) {
        return this.findTypeOfWithParentType(
          arg,
          this.assertionRule.args[Math.min(index, lastIndex)].type
        );
      }, this);
    },
    _getAssertionIndices() {
      if (!this._assertionIndices) {
        const assertionIndices = [];
        const args = this.args;
        let currentAssertionRule = this.assertionRule;
        let offset = 0;
        // eslint-disable-next-line no-labels
        OUTER: while (true) {
          if (
            currentAssertionRule.args.length > 1 &&
            isAssertionArg(
              currentAssertionRule.args[currentAssertionRule.args.length - 2]
            )
          ) {
            assertionIndices.push(
              offset + currentAssertionRule.args.length - 2
            );
            const suffixAssertions = findSuffixAssertions(
              args[offset + currentAssertionRule.args.length - 2],
              expect
            );
            if (suffixAssertions) {
              for (let i = 0; i < suffixAssertions.length; i += 1) {
                if (suffixAssertions[i].args.some(isAssertionArg)) {
                  offset += currentAssertionRule.args.length - 1;
                  currentAssertionRule = suffixAssertions[i];
                  // eslint-disable-next-line no-labels
                  continue OUTER;
                }
              }
            }
          }
          // No further assertions found,
          break;
        }
        this._assertionIndices = assertionIndices;
      }
      return this._assertionIndices;
    }
  };

  if (Object.__defineGetter__) {
    Object.defineProperty(wrappedExpectProto, 'subjectType', {
      enumerable: true,
      get() {
        return this.assertionRule && this._getSubjectType();
      }
    });

    Object.defineProperty(wrappedExpectProto, 'argTypes', {
      enumerable: true,
      get() {
        return this.assertionRule && this._getArgTypes();
      }
    });
  }

  utils.setPrototypeOfOrExtend(wrappedExpectProto, Function.prototype);
  return wrappedExpectProto;
};
<|endoftext|>


<commit_before>const AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});
const ses = new AWS.SES({apiVersion: '2010-12-01'});
const checkWhitelist = require('../check-whitelist');
const Boom = require('boom');

class SesDriver {
  send(emailObject) {
    return new Promise((resolve, reject) => {
      if (!emailObject.to) {
        return reject(new Error('no to address provided'));
      }

      if (!emailObject.subject) {
        return reject(new Error('no subject provided'));
      }

      if (!emailObject.text && !emailObject.html) {
        return reject(new Error('no text or html body provided'));
      }

      if (emailObject.attachments) {
        return reject(new Error('ses driver does not currently support attachments'));
      }

      const params = {
        Destination: { ToAddresses: [checkWhitelist(emailObject.to, reject)] },
        Message: {
          Body: {
            Html: {
              Data: emailObject.html
            },
          },
          Subject: {
            Data: emailObject.subject,
          },
        },
        Source: emailObject.from || 'no-reply@' + process.env.OIDC_EMAIL_DOMAIN,
      };

      ses.sendEmail(params).promise().then(result => {
        resolve(result);
      })
        .catch(err => {
          reject(Boom.wrap(err, err.statusCode));
        });
    });
  }
}

module.exports = SesDriver;
<commit_msg>292 | Dont overwrite the AWS region in the SES driver<commit_after>const AWS = require('aws-sdk');
const ses = new AWS.SES({apiVersion: '2010-12-01'});
const checkWhitelist = require('../check-whitelist');
const Boom = require('boom');

class SesDriver {
  send(emailObject) {
    return new Promise((resolve, reject) => {
      if (!emailObject.to) {
        return reject(new Error('no to address provided'));
      }

      if (!emailObject.subject) {
        return reject(new Error('no subject provided'));
      }

      if (!emailObject.text && !emailObject.html) {
        return reject(new Error('no text or html body provided'));
      }

      if (emailObject.attachments) {
        return reject(new Error('ses driver does not currently support attachments'));
      }

      const params = {
        Destination: { ToAddresses: [checkWhitelist(emailObject.to, reject)] },
        Message: {
          Body: {
            Html: {
              Data: emailObject.html
            },
          },
          Subject: {
            Data: emailObject.subject,
          },
        },
        Source: emailObject.from || 'no-reply@' + process.env.OIDC_EMAIL_DOMAIN,
      };

      ses.sendEmail(params).promise().then(result => {
        resolve(result);
      })
        .catch(err => {
          reject(Boom.wrap(err, err.statusCode));
        });
    });
  }
}

module.exports = SesDriver;
<|endoftext|>