<commit_before>import { queryParameters, fetchJson } from '../util/fetch';
import {
    GET_LIST,
    GET_MATCHING,
    GET_ONE,
    GET_MANY,
    GET_MANY_REFERENCE,
    CREATE,
    UPDATE,
    DELETE,
} from './types';

/**
 * Maps admin-on-rest queries to a json-server powered REST API
 *
 * @see https://github.com/typicode/json-server
 * @example
 * GET_LIST     => GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24
 * GET_MATCHING => GET http://my.api.url/posts?title=bar
 * GET_ONE      => GET http://my.api.url/posts/123
 * GET_MANY     => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * UPDATE       => PUT http://my.api.url/posts/123
 * CREATE       => POST http://my.api.url/posts/123
 * DELETE       => DELETE http://my.api.url/posts/123
 */
export default (apiUrl, httpClient = fetchJson) => {
    /**
     * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
     * @param {String} resource Name of the resource to fetch, e.g. 'posts'
     * @param {Object} params The REST request params, depending on the type
     * @returns {Object} { url, options } The HTTP request parameters
     */
    const convertRESTRequestToHTTP = (type, resource, params) => {
        let url = '';
        const options = {};
        switch (type) {
        case GET_LIST: {
            const { page, perPage } = params.pagination;
            const { field, order } = params.sort;
            const query = {
                ...params.filter,
                _sort: field,
                _order: order,
                _start: (page - 1) * perPage,
                _end: page * perPage - 1,
            };
            url = `${apiUrl}/${resource}?${queryParameters(query)}`;
            break;
        }
        case GET_MATCHING: {
            url = `${apiUrl}/${resource}?${queryParameters(params.filter)}`;
            break;
        }
        case GET_ONE:
            url = `${apiUrl}/${resource}/${params.id}`;
            break;
        case GET_MANY_REFERENCE:
            url = `${apiUrl}/${resource}?${queryParameters({ [params.target]: params.id })}`;
            break;
        case UPDATE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'PUT';
            options.body = JSON.stringify(params.data);
            break;
        case CREATE:
            url = `${apiUrl}/${resource}`;
            options.method = 'POST';
            options.body = JSON.stringify(params.data);
            break;
        case DELETE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'DELETE';
            break;
        default:
            throw new Error(`Unsupported fetch action type ${type}`);
        }
        return { url, options };
    };

    /**
     * @param {Object} response HTTP response from fetch()
     * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
     * @param {String} resource Name of the resource to fetch, e.g. 'posts'
     * @param {Object} params The REST request params, depending on the type
     * @returns {Object} REST response
     */
    const convertHTTPResponseToREST = (response, type, resource, params) => {
        const { headers, json } = response;
        switch (type) {
        case GET_LIST:
            if (!headers.has('x-total-count')) {
                throw new Error('The X-Total-Count header is missing in the HTTP Response. This header is necessary for pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Allow-Headers header?');
            }
            return {
                data: json.map(x => x),
                total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
            };
        case CREATE:
            return { ...params.data, id: json.id };
        default:
            return json;
        }
    };

    /**
     * @param {string} type Request type, e.g GET_LIST
     * @param {string} resource Resource name, e.g. "posts"
     * @param {Object} payload Request parameters. Depends on the request type
     * @returns {Promise} the Promise for a REST response
     */
    return (type, resource, params) => {
        // json-server doesn't handle WHERE IN requests, so we fallback to calling GET_ONE n times instead
        if (type === GET_MANY) {
            return Promise.all(params.ids.map(id => fetchJson(`${apiUrl}/${resource}/${id}`)))
                .then(responses => responses.map(response => response.json));
        }
        const { url, options } = convertRESTRequestToHTTP(type, resource, params);
        return httpClient(url, options)
            .then(response => convertHTTPResponseToREST(response, type, resource, params));
    };
};
<commit_msg>Use httpHeader for GET_MANY<commit_after>import { queryParameters, fetchJson } from '../util/fetch';
import {
    GET_LIST,
    GET_MATCHING,
    GET_ONE,
    GET_MANY,
    GET_MANY_REFERENCE,
    CREATE,
    UPDATE,
    DELETE,
} from './types';

/**
 * Maps admin-on-rest queries to a json-server powered REST API
 *
 * @see https://github.com/typicode/json-server
 * @example
 * GET_LIST     => GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24
 * GET_MATCHING => GET http://my.api.url/posts?title=bar
 * GET_ONE      => GET http://my.api.url/posts/123
 * GET_MANY     => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * UPDATE       => PUT http://my.api.url/posts/123
 * CREATE       => POST http://my.api.url/posts/123
 * DELETE       => DELETE http://my.api.url/posts/123
 */
export default (apiUrl, httpClient = fetchJson) => {
    /**
     * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
     * @param {String} resource Name of the resource to fetch, e.g. 'posts'
     * @param {Object} params The REST request params, depending on the type
     * @returns {Object} { url, options } The HTTP request parameters
     */
    const convertRESTRequestToHTTP = (type, resource, params) => {
        let url = '';
        const options = {};
        switch (type) {
        case GET_LIST: {
            const { page, perPage } = params.pagination;
            const { field, order } = params.sort;
            const query = {
                ...params.filter,
                _sort: field,
                _order: order,
                _start: (page - 1) * perPage,
                _end: page * perPage - 1,
            };
            url = `${apiUrl}/${resource}?${queryParameters(query)}`;
            break;
        }
        case GET_MATCHING: {
            url = `${apiUrl}/${resource}?${queryParameters(params.filter)}`;
            break;
        }
        case GET_ONE:
            url = `${apiUrl}/${resource}/${params.id}`;
            break;
        case GET_MANY_REFERENCE:
            url = `${apiUrl}/${resource}?${queryParameters({ [params.target]: params.id })}`;
            break;
        case UPDATE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'PUT';
            options.body = JSON.stringify(params.data);
            break;
        case CREATE:
            url = `${apiUrl}/${resource}`;
            options.method = 'POST';
            options.body = JSON.stringify(params.data);
            break;
        case DELETE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'DELETE';
            break;
        default:
            throw new Error(`Unsupported fetch action type ${type}`);
        }
        return { url, options };
    };

    /**
     * @param {Object} response HTTP response from fetch()
     * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
     * @param {String} resource Name of the resource to fetch, e.g. 'posts'
     * @param {Object} params The REST request params, depending on the type
     * @returns {Object} REST response
     */
    const convertHTTPResponseToREST = (response, type, resource, params) => {
        const { headers, json } = response;
        switch (type) {
        case GET_LIST:
            if (!headers.has('x-total-count')) {
                throw new Error('The X-Total-Count header is missing in the HTTP Response. This header is necessary for pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Allow-Headers header?');
            }
            return {
                data: json.map(x => x),
                total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
            };
        case CREATE:
            return { ...params.data, id: json.id };
        default:
            return json;
        }
    };

    /**
     * @param {string} type Request type, e.g GET_LIST
     * @param {string} resource Resource name, e.g. "posts"
     * @param {Object} payload Request parameters. Depends on the request type
     * @returns {Promise} the Promise for a REST response
     */
    return (type, resource, params) => {
        // json-server doesn't handle WHERE IN requests, so we fallback to calling GET_ONE n times instead
        if (type === GET_MANY) {
            return Promise.all(params.ids.map(id => httpClient(`${apiUrl}/${resource}/${id}`)))
                .then(responses => responses.map(response => response.json));
        }
        const { url, options } = convertRESTRequestToHTTP(type, resource, params);
        return httpClient(url, options)
            .then(response => convertHTTPResponseToREST(response, type, resource, params));
    };
};
<|endoftext|>


<commit_before>'use strict';

const hProto = require('../interface/result.h').prototype;
const sym = require('../interface/result-sym.h');

hProto.orElse = function ($resultEmitter) {
    return this[sym.isOk]
        ? this
        : hProto.fromTry($resultEmitter(this[sym.value]))
    ;
};
<commit_msg>fix bug<commit_after>'use strict';

const h = require('../interface/result.h');
const hProto = h.prototype;
const sym = require('../interface/result-sym.h');

hProto.orElse = function ($resultEmitter) {
    return this[sym.isOk]
        ? this
        : h.fromTry($resultEmitter(this[sym.value]))
    ;
};
<|endoftext|>


<commit_before>/*\
title: $:/plugins/inymsocks/MathyThing/sumfield.js
type: application/javascript
module-type: widget

Sum the values in a specified field and store the result in another field

<$sumfield filter='[tag[sum]]' sumfield='sum_field' storefield='store_field'/>

This is an edited version of the list widget from TiddlyWiki5

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var SumFieldWidget = function(parseTreeNode,options) {
	// Main initialisation inherited from widget.js
	this.initialise(parseTreeNode,options);
};

/*
Inherit from the base widget class
*/
SumFieldWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
SumFieldWidget.prototype.render = function(parent,nextSibling) {
	this.computeAttributes();
	this.execute();
};

/*
Compute the internal state of the widget
*/
SumFieldWidget.prototype.execute = function() {
	// Get attributes
	this.actionTiddler = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
	this.sumField = this.getAttribute("sumfield");
	this.storeField = this.getAttribute("storefield");
	this.storeIndex = this.getAttribute("index");
	this.defaultValue = this.getAttribute("defaultvalue",0);
	// Compose the list elements
	this.list = this.getTiddlerList();
	// Get current value
	var storetiddler = this.wiki.getTiddler(this.actionTiddler);
	var currentState = storetiddler.getFieldString(this.storeField);
	// Check for an empty list, if the list isn't empty compute the sum
	if(this.list.length === 0) {
	  output = this.defaultValue; //return the default value when there is nothing to sum, if it isn't set than return 0
	} else {
	  var output = 0;
	  for (var i = 0; i < this.list.length; i++) {
	    var tidtitle = this.list[i];
	    var tiddler = this.wiki.getTiddler(tidtitle);
	    if ( !isNaN(parseFloat(tiddler.getFieldString(this.prodField))) && isFinite(tiddler.getFieldString(this.prodField)) ) {
	    	output = output + Number(tiddler.getFieldString(this.sumField));
		}
	  }
	}
        // If the sum has changed then write to the field
	this.output = String(output);
	if (this.output === String(storetiddler.getFieldString(this.storeField))) {
	} else {
	  this.wiki.setText(this.actionTiddler,this.storeField,this.storeIndex,this.output);
	}
};

/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
SumFieldWidget.prototype.refresh = function(changedTiddlers) {
	var changedAttributes = this.computeAttributes();
	var output = 0;
	this.list = this.getTiddlerList();
	for (var i = 0; i < this.list.length; i++) {
	  var tidtitle = this.list[i];
	  var tiddler = this.wiki.getTiddler(tidtitle);
	  if ( !isNaN(parseFloat(tiddler.getFieldString(this.prodField))) && isFinite(tiddler.getFieldString(this.prodField)) ) {
	  	output = output + Number(tiddler.getFieldString(this.sumField));
	  }
	}
	var storetiddler = this.wiki.getTiddler(this.actionTiddler);
	// Completely rerender if any of our attributes have changed
	if (String(output) != String(storetiddler.getFieldString(this.storeField))) {
		this.refreshSelf();
		return true;
	} else if(this.stateTitle && changedTiddlers[this.stateTitle]) {
		this.readState();
		return true;
	}
	return false;
};

SumFieldWidget.prototype.getTiddlerList = function() {
	var defaultFilter = "[!is[system]is[system]]"; // this will always return an empty list and is always valid, so default behavior is to return an empty list
	return this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
};

exports.sumfield = SumFieldWidget;

})();
<commit_msg>Fixed a typo that prevented sumfield.js from working<commit_after>/*\
title: $:/plugins/inymsocks/MathyThing/sumfield.js
type: application/javascript
module-type: widget

Sum the values in a specified field and store the result in another field

<$sumfield filter='[tag[sum]]' sumfield='sum_field' storefield='store_field'/>

This is an edited version of the list widget from TiddlyWiki5

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var SumFieldWidget = function(parseTreeNode,options) {
	// Main initialisation inherited from widget.js
	this.initialise(parseTreeNode,options);
};

/*
Inherit from the base widget class
*/
SumFieldWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
SumFieldWidget.prototype.render = function(parent,nextSibling) {
	this.computeAttributes();
	this.execute();
};

/*
Compute the internal state of the widget
*/
SumFieldWidget.prototype.execute = function() {
	// Get attributes
	this.actionTiddler = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
	this.sumField = this.getAttribute("sumfield");
	this.storeField = this.getAttribute("storefield");
	this.storeIndex = this.getAttribute("index");
	this.defaultValue = this.getAttribute("defaultvalue",0);
	// Compose the list elements
	this.list = this.getTiddlerList();
	// Get current value
	var storetiddler = this.wiki.getTiddler(this.actionTiddler);
	var currentState = storetiddler.getFieldString(this.storeField);
	// Check for an empty list, if the list isn't empty compute the sum
	if(this.list.length === 0) {
	  output = this.defaultValue; //return the default value when there is nothing to sum, if it isn't set than return 0
	} else {
	  var output = 0;
	  for (var i = 0; i < this.list.length; i++) {
	    var tidtitle = this.list[i];
	    var tiddler = this.wiki.getTiddler(tidtitle);
	    if ( !isNaN(parseFloat(tiddler.getFieldString(this.sumField))) && isFinite(tiddler.getFieldString(this.sumField)) ) {
	    	output = output + Number(tiddler.getFieldString(this.sumField));
		}
	  }
	}
        // If the sum has changed then write to the field
	this.output = String(output);
	if (this.output === String(storetiddler.getFieldString(this.storeField))) {
	} else {
	  this.wiki.setText(this.actionTiddler,this.storeField,this.storeIndex,this.output);
	}
};

/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
SumFieldWidget.prototype.refresh = function(changedTiddlers) {
	var changedAttributes = this.computeAttributes();
	var output = 0;
	this.list = this.getTiddlerList();
	for (var i = 0; i < this.list.length; i++) {
	  var tidtitle = this.list[i];
	  var tiddler = this.wiki.getTiddler(tidtitle);
	  if ( !isNaN(parseFloat(tiddler.getFieldString(this.sumField))) && isFinite(tiddler.getFieldString(this.sumField)) ) {
	  	output = output + Number(tiddler.getFieldString(this.sumField));
	  }
	}
	var storetiddler = this.wiki.getTiddler(this.actionTiddler);
	// Completely rerender if any of our attributes have changed
	if (String(output) != String(storetiddler.getFieldString(this.storeField))) {
		this.refreshSelf();
		return true;
	} else if(this.stateTitle && changedTiddlers[this.stateTitle]) {
		this.readState();
		return true;
	}
	return false;
};

SumFieldWidget.prototype.getTiddlerList = function() {
	var defaultFilter = "[!is[system]is[system]]"; // this will always return an empty list and is always valid, so default behavior is to return an empty list
	return this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
};

exports.sumfield = SumFieldWidget;

})();
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2013 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

var angular = angular || null;

(function() {

    var root = this;
    var _ = root._.noConflict();
    var $ = root.AmarajQuery;

    var LanguageSelectorController = function($scope, SubtitleStorage, SubtitleListFinder) {
        /**
         * This controller is responsible for the language and version selector
         * widget.  The widget allows the user to select a reference language and
         * version when translating subtitles into another language.
         *
         * The $scope contains 'languages' and 'versions'.  Each list is
         * represented in the UI as a <select> element.  The selected language or
         * version is stored on the $scope as a 'language' and 'version' model.
         *
         * Whenever the language selection is changed, we update the list of
         * versions.  When a new version is selected, we retrieve the subtitles
         * (either from memory or from the API via ajax) and display them in the
         * side panel.
         */

        $scope.languageSelectChanged = function(lang) {
            var vers, language;

            if (lang) {
                language = lang;
            } else {
                language = $scope.language;
            }

            if (!language) {
                return;
            }

            vers =_.sortBy(language.versions, function(item) {
                return item.version_no;
            });

            $scope.versions = vers.reverse();

            if (vers.length && vers.length > 0) {
                $scope.version = $scope.versions[0];
            }
        };
        $scope.setReferenceSubs = function(subtitles) {
            if (!$scope.refSubList) {
                $scope.refSubList = SubtitleListFinder.get('reference-subtitle-set');
            }
            $scope.refSubList.scope.onSubtitlesFetched(subtitles);
        };
        $scope.versionChanged = function(newVersion) {

            if (!newVersion) {
                return;
            }

            var subtitlesXML = newVersion.subtitlesXML;

            if (!subtitlesXML) {
                SubtitleStorage.getSubtitles($scope.language.code,
                                             newVersion.version_no,
                                             function(subtitles) {
                    $scope.version.subtitlesXML = subtitles.subtitlesXML;
                    $scope.setReferenceSubs(subtitles);
                });
            } else {
                $scope.setReferenceSubs(newVersion);
            }
        };

        SubtitleStorage.getLanguages(function(languages) {
            $scope.languages = languages;
            $scope.language = _.find(languages, function(item) {
                return item.editingLanguage;
            });
            $scope.languageSelectChanged($scope.language);
        });

        $scope.$watch('version', $scope.versionChanged);
    };
    var SaveSessionController = function($scope, SubtitleListFinder, SubtitleStorage) {

        $scope.cancelAndClose = function($event) {

            $event.preventDefault();

            $scope.$root.$emit('show-loading-modal', 'Canceled. Redirecting…');
            window.location = $scope.closeURL;

        };
        $scope.getNotes = function() {
            var collabScope = angular.element($('section.collab').get(0)).scope();
            return collabScope.notes || '';
        };
        $scope.saveAndApprove = function($event) {

            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.status = 'approving';

                    SubtitleStorage.approveTask(response, $scope.getNotes()).then(function onSuccess(response) {

                        $scope.$root.$emit('show-loading-modal', 'Subtitles saved, task approved. Redirecting…');
                        window.location = $scope.closeURL;

                    }, function onError() {
                        $scope.status = 'error';
                        window.alert('Sorry, there was an error...');
                    });
                }
            });

        };
        $scope.saveAndClose = function($event) {

            $event.preventDefault();

            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.$root.$emit('show-loading-modal', 'Subtitles saved! Redirecting…');
                    window.location = $scope.closeURL;

                }
            });
        };
        $scope.saveAndSendBack = function() {
            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.status = 'sending-back';

                    SubtitleStorage.sendBackTask(response, $scope.getNotes()).then(function onSuccess(response) {

                        $scope.$root.$emit('show-loading-modal', 'Subtitles saved, task sent back. Redirecting…');
                        window.location = $scope.closeURL;

                    }, function onError() {
                        $scope.status = 'error';
                        window.alert('Sorry, there was an error...');
                    });

                }
            });
        };
        $scope.saveSession = function() {
            if ($scope.status !== 'saving') {
                $scope.status = 'saving';

                var promise = SubtitleListFinder.get('working-subtitle-set').scope.saveSubtitles();

                promise.then(function onSuccess(response) {
                    $scope.status = 'saved';
                }, function onError() {
                    $scope.status = 'error';
                    window.alert('Sorry, there was an error...');
                });

                return promise;
            }
        };
        $scope.setCloseStates = function() {
            var subtitleListScope = SubtitleListFinder.get('working-subtitle-set').scope;

            $scope.fromOldEditor = window.location.search.indexOf('from-old-editor') !== -1 ? true : false;

            if ($scope.fromOldEditor) {
                $scope.closeText = 'Return';
                $scope.closeURL = '/onsite_widget/?config=' + window.location.search.split('config=')[1];
            } else {
                $scope.closeText = 'Close';
                $scope.closeURL = '/videos/' + subtitleListScope.videoID + '/' +
                    subtitleListScope.languageCode + '/';
            }
        };

        $scope.$root.$on('approve-task', function() {
            $scope.saveAndApprove();
        });
        $scope.$root.$on('send-back-task', function() {
            $scope.saveAndSendBack();
        });
        $scope.$root.$on('subtitles-fetched', function() {
            $scope.setCloseStates();
        });
        $scope.$root.$on('work-done', function() {
            $scope.canSave = '';
            $scope.$digest();
        });

    };
    var SubtitleListController = function($scope, $timeout, SubtitleStorage) {
        /**
         * Responsible for everything that touches subtitles as a group,
         * souch as populating the list with actual data, removing subs,
         * adding subs.
         * @param $scope
         * @param SubtitleStorage
         * @constructor
         */

        $scope.addSubtitle = function(index, attrs, content, focus) {

            // Add the subtitle directly to the DFXP instance.
            var newSubtitle = $scope.parser.addSubtitle(index, attrs, content);

            // If we want to focus the subtitle after it's been added, set
            // the index here.
            if (focus) {
                $scope.focusIndex = $scope.parser.getSubtitleIndex(newSubtitle, $scope.parser.getSubtitles().get());

            // Otherwise, reset the focusIndex.
            } else {
                $scope.focusIndex = null;
            }

            // Update the subtitles on the list scope.
            $scope.updateParserSubtitles();
        };
        $scope.getSubtitleListHeight = function() {
            return $(window).height() - 359;
        };
        $scope.getSubtitles = function(languageCode, versionNumber) {

            // If this version has no default source translation language
            // it will be empty, in which case we want to wait for user
            // interaction to request a reference subtitle set.
            if (!languageCode || !versionNumber) {
                $scope.status = 'idle';
                return;
            }

            $scope.status = 'loading';

            SubtitleStorage.getSubtitles(languageCode, versionNumber, function(subtitles) {
                $scope.onSubtitlesFetched(subtitles);
            });

        };
        $scope.onSubtitlesFetched = function (subtitles) {

            // Save the title and description to this scope.
            $scope.videoTitle = subtitles.title;
            $scope.videoDescription = subtitles.description;

            // Set up a new parser instance with this DFXP XML set.
            this.dfxpWrapper = new root.AmaraDFXPParser();
            this.dfxpWrapper.init(subtitles.subtitlesXML);

            // Reference the parser and instance on the scope so we can access it via
            // the templates.
            $scope.parser = this.dfxpWrapper;
            $scope.subtitles = $scope.parser.getSubtitles().get();

            $scope.status = 'ready';

            // When we have subtitles for an editable set, broadcast it.
            $timeout(function() {
                if ($scope.isEditable) {
                    $scope.$root.$broadcast('subtitles-fetched');
                }
            });
        };
        $scope.removeSubtitle = function(subtitle) {
            $scope.parser.removeSubtitle(subtitle);
            $scope.updateParserSubtitles();
        };
        $scope.saveSubtitles = function() {
            $scope.status = 'saving';
            return SubtitleStorage.saveSubtitles($scope.videoID,
                                          $scope.languageCode,
                                          $scope.parser.xmlToString(true, true));
        };
        $scope.setLanguageCode = function(languageCode) {
            $scope.languageCode = languageCode;
        };
        $scope.setVideoID = function(videoID) {
            $scope.videoID = videoID;
        };
        $scope.updateParserSubtitles = function() {
            $scope.subtitles = $scope.parser.getSubtitles().get();
        };

        $scope.$watch($scope.getSubtitleListHeight, function(newHeight) {
            $($('div.subtitles').height(newHeight));
        });

        window.onresize = function() {
            $scope.$digest();
        };
    };
    var SubtitleListHelperController = function($scope) {

        $scope.isEditingAny = false;

        $scope.$root.$on('editing', function() {
            $scope.isEditingAny = true;
            $scope.$digest();
        });
        $scope.$root.$on('editingDone', function() {
            $scope.isEditingAny = false;
            $scope.$digest();
        });
    };
    var SubtitleListItemController = function($scope) {
        /**
         * Responsible for actions on one subtitle: editing, selecting.
         * @param $scope
         * @constructor
         */

        var initialText;

        $scope.empty = false;
        $scope.isEditing = false;
        $scope.showStartTime = $scope.parser.startTimeFromNode($scope.subtitle) > 0;

        $scope.finishEditingMode = function(newValue) {

            $scope.isEditing = false;

            // Tell the root scope that we're no longer editing, now.
            $scope.$root.$emit('editingDone');

            var content = $scope.parser.content($scope.subtitle, newValue);

            if (content !== initialText) {
                $scope.$root.$emit('work-done');
            }
        };
        $scope.getSubtitleIndex = function() {
            return $scope.parser.getSubtitleIndex($scope.subtitle, $scope.subtitles);
        };
        $scope.startEditingMode = function() {

            initialText = $scope.parser.content($scope.subtitle);

            $scope.isEditing = true;

            // Tell the root scope that we're editing, now.
            $scope.$root.$emit('editing');

            return initialText;
        };

        $scope.$root.$on('subtitles-fetched', function() {
            // When subtitles are first retrieved, we need to set up the amarasubtitle
            // on the video and bind to this scope.
            //
            // This will happen on the video controller. Just throw an event stating that
            // we're ready.

            // Only emit the event on editable subtitles. We don't want to initialize
            // Popcorn subtitles for the non-editable set.
            if ($scope.$parent.isEditable) {
                $scope.$root.$emit('subtitle-ready', $scope);
            }
        });
    };
    var VideoTitleController = function($scope, SubtitleListFinder) {

        // Once the working subtitles have been fetched, set the title and description.
        $scope.$root.$on('subtitles-fetched', function() {

            // Reference the actual scope in the template so we can get automatic binding
            // on the title and description.
            $scope.workingSubtitles = SubtitleListFinder.get('working-subtitle-set').scope;

        });

    };

    root.LanguageSelectorController = LanguageSelectorController;
    root.SaveSessionController = SaveSessionController;
    root.SubtitleListController = SubtitleListController;
    root.SubtitleListHelperController = SubtitleListHelperController;
    root.SubtitleListItemController = SubtitleListItemController;
    root.VideoTitleController = VideoTitleController;

}).call(this);'hi'
<commit_msg>Yea we don't need this.<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2013 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

var angular = angular || null;

(function() {

    var root = this;
    var _ = root._.noConflict();
    var $ = root.AmarajQuery;

    var LanguageSelectorController = function($scope, SubtitleStorage, SubtitleListFinder) {
        /**
         * This controller is responsible for the language and version selector
         * widget.  The widget allows the user to select a reference language and
         * version when translating subtitles into another language.
         *
         * The $scope contains 'languages' and 'versions'.  Each list is
         * represented in the UI as a <select> element.  The selected language or
         * version is stored on the $scope as a 'language' and 'version' model.
         *
         * Whenever the language selection is changed, we update the list of
         * versions.  When a new version is selected, we retrieve the subtitles
         * (either from memory or from the API via ajax) and display them in the
         * side panel.
         */

        $scope.languageSelectChanged = function(lang) {
            var vers, language;

            if (lang) {
                language = lang;
            } else {
                language = $scope.language;
            }

            if (!language) {
                return;
            }

            vers =_.sortBy(language.versions, function(item) {
                return item.version_no;
            });

            $scope.versions = vers.reverse();

            if (vers.length && vers.length > 0) {
                $scope.version = $scope.versions[0];
            }
        };
        $scope.setReferenceSubs = function(subtitles) {
            if (!$scope.refSubList) {
                $scope.refSubList = SubtitleListFinder.get('reference-subtitle-set');
            }
            $scope.refSubList.scope.onSubtitlesFetched(subtitles);
        };
        $scope.versionChanged = function(newVersion) {

            if (!newVersion) {
                return;
            }

            var subtitlesXML = newVersion.subtitlesXML;

            if (!subtitlesXML) {
                SubtitleStorage.getSubtitles($scope.language.code,
                                             newVersion.version_no,
                                             function(subtitles) {
                    $scope.version.subtitlesXML = subtitles.subtitlesXML;
                    $scope.setReferenceSubs(subtitles);
                });
            } else {
                $scope.setReferenceSubs(newVersion);
            }
        };

        SubtitleStorage.getLanguages(function(languages) {
            $scope.languages = languages;
            $scope.language = _.find(languages, function(item) {
                return item.editingLanguage;
            });
            $scope.languageSelectChanged($scope.language);
        });

        $scope.$watch('version', $scope.versionChanged);
    };
    var SaveSessionController = function($scope, SubtitleListFinder, SubtitleStorage) {

        $scope.cancelAndClose = function($event) {

            $event.preventDefault();

            $scope.$root.$emit('show-loading-modal', 'Canceled. Redirecting…');
            window.location = $scope.closeURL;

        };
        $scope.getNotes = function() {
            var collabScope = angular.element($('section.collab').get(0)).scope();
            return collabScope.notes || '';
        };
        $scope.saveAndApprove = function($event) {

            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.status = 'approving';

                    SubtitleStorage.approveTask(response, $scope.getNotes()).then(function onSuccess(response) {

                        $scope.$root.$emit('show-loading-modal', 'Subtitles saved, task approved. Redirecting…');
                        window.location = $scope.closeURL;

                    }, function onError() {
                        $scope.status = 'error';
                        window.alert('Sorry, there was an error...');
                    });
                }
            });

        };
        $scope.saveAndClose = function($event) {

            $event.preventDefault();

            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.$root.$emit('show-loading-modal', 'Subtitles saved! Redirecting…');
                    window.location = $scope.closeURL;

                }
            });
        };
        $scope.saveAndSendBack = function() {
            $scope.saveSession().then(function(response) {
                if ($scope.status === 'saved') {

                    $scope.status = 'sending-back';

                    SubtitleStorage.sendBackTask(response, $scope.getNotes()).then(function onSuccess(response) {

                        $scope.$root.$emit('show-loading-modal', 'Subtitles saved, task sent back. Redirecting…');
                        window.location = $scope.closeURL;

                    }, function onError() {
                        $scope.status = 'error';
                        window.alert('Sorry, there was an error...');
                    });

                }
            });
        };
        $scope.saveSession = function() {
            if ($scope.status !== 'saving') {
                $scope.status = 'saving';

                var promise = SubtitleListFinder.get('working-subtitle-set').scope.saveSubtitles();

                promise.then(function onSuccess(response) {
                    $scope.status = 'saved';
                }, function onError() {
                    $scope.status = 'error';
                    window.alert('Sorry, there was an error...');
                });

                return promise;
            }
        };
        $scope.setCloseStates = function() {
            var subtitleListScope = SubtitleListFinder.get('working-subtitle-set').scope;

            $scope.fromOldEditor = window.location.search.indexOf('from-old-editor') !== -1 ? true : false;

            if ($scope.fromOldEditor) {
                $scope.closeText = 'Return';
                $scope.closeURL = '/onsite_widget/?config=' + window.location.search.split('config=')[1];
            } else {
                $scope.closeText = 'Close';
                $scope.closeURL = '/videos/' + subtitleListScope.videoID + '/' +
                    subtitleListScope.languageCode + '/';
            }
        };

        $scope.$root.$on('approve-task', function() {
            $scope.saveAndApprove();
        });
        $scope.$root.$on('send-back-task', function() {
            $scope.saveAndSendBack();
        });
        $scope.$root.$on('subtitles-fetched', function() {
            $scope.setCloseStates();
        });
        $scope.$root.$on('work-done', function() {
            $scope.canSave = '';
            $scope.$digest();
        });

    };
    var SubtitleListController = function($scope, $timeout, SubtitleStorage) {
        /**
         * Responsible for everything that touches subtitles as a group,
         * souch as populating the list with actual data, removing subs,
         * adding subs.
         * @param $scope
         * @param SubtitleStorage
         * @constructor
         */

        $scope.addSubtitle = function(index, attrs, content, focus) {

            // Add the subtitle directly to the DFXP instance.
            var newSubtitle = $scope.parser.addSubtitle(index, attrs, content);

            // If we want to focus the subtitle after it's been added, set
            // the index here.
            if (focus) {
                $scope.focusIndex = $scope.parser.getSubtitleIndex(newSubtitle, $scope.parser.getSubtitles().get());

            // Otherwise, reset the focusIndex.
            } else {
                $scope.focusIndex = null;
            }

            // Update the subtitles on the list scope.
            $scope.updateParserSubtitles();
        };
        $scope.getSubtitleListHeight = function() {
            return $(window).height() - 359;
        };
        $scope.getSubtitles = function(languageCode, versionNumber) {

            // If this version has no default source translation language
            // it will be empty, in which case we want to wait for user
            // interaction to request a reference subtitle set.
            if (!languageCode || !versionNumber) {
                $scope.status = 'idle';
                return;
            }

            $scope.status = 'loading';

            SubtitleStorage.getSubtitles(languageCode, versionNumber, function(subtitles) {
                $scope.onSubtitlesFetched(subtitles);
            });

        };
        $scope.onSubtitlesFetched = function (subtitles) {

            // Save the title and description to this scope.
            $scope.videoTitle = subtitles.title;
            $scope.videoDescription = subtitles.description;

            // Set up a new parser instance with this DFXP XML set.
            this.dfxpWrapper = new root.AmaraDFXPParser();
            this.dfxpWrapper.init(subtitles.subtitlesXML);

            // Reference the parser and instance on the scope so we can access it via
            // the templates.
            $scope.parser = this.dfxpWrapper;
            $scope.subtitles = $scope.parser.getSubtitles().get();

            $scope.status = 'ready';

            // When we have subtitles for an editable set, broadcast it.
            $timeout(function() {
                if ($scope.isEditable) {
                    $scope.$root.$broadcast('subtitles-fetched');
                }
            });
        };
        $scope.removeSubtitle = function(subtitle) {
            $scope.parser.removeSubtitle(subtitle);
            $scope.updateParserSubtitles();
        };
        $scope.saveSubtitles = function() {
            $scope.status = 'saving';
            return SubtitleStorage.saveSubtitles($scope.videoID,
                                          $scope.languageCode,
                                          $scope.parser.xmlToString(true, true));
        };
        $scope.setLanguageCode = function(languageCode) {
            $scope.languageCode = languageCode;
        };
        $scope.setVideoID = function(videoID) {
            $scope.videoID = videoID;
        };
        $scope.updateParserSubtitles = function() {
            $scope.subtitles = $scope.parser.getSubtitles().get();
        };

        $scope.$watch($scope.getSubtitleListHeight, function(newHeight) {
            $($('div.subtitles').height(newHeight));
        });

        window.onresize = function() {
            $scope.$digest();
        };
    };
    var SubtitleListHelperController = function($scope) {

        $scope.isEditingAny = false;

        $scope.$root.$on('editing', function() {
            $scope.isEditingAny = true;
            $scope.$digest();
        });
        $scope.$root.$on('editingDone', function() {
            $scope.isEditingAny = false;
            $scope.$digest();
        });
    };
    var SubtitleListItemController = function($scope) {
        /**
         * Responsible for actions on one subtitle: editing, selecting.
         * @param $scope
         * @constructor
         */

        var initialText;

        $scope.empty = false;
        $scope.isEditing = false;
        $scope.showStartTime = $scope.parser.startTimeFromNode($scope.subtitle) > 0;

        $scope.finishEditingMode = function(newValue) {

            $scope.isEditing = false;

            // Tell the root scope that we're no longer editing, now.
            $scope.$root.$emit('editingDone');

            var content = $scope.parser.content($scope.subtitle, newValue);

            if (content !== initialText) {
                $scope.$root.$emit('work-done');
            }
        };
        $scope.getSubtitleIndex = function() {
            return $scope.parser.getSubtitleIndex($scope.subtitle, $scope.subtitles);
        };
        $scope.startEditingMode = function() {

            initialText = $scope.parser.content($scope.subtitle);

            $scope.isEditing = true;

            // Tell the root scope that we're editing, now.
            $scope.$root.$emit('editing');

            return initialText;
        };

        $scope.$root.$on('subtitles-fetched', function() {
            // When subtitles are first retrieved, we need to set up the amarasubtitle
            // on the video and bind to this scope.
            //
            // This will happen on the video controller. Just throw an event stating that
            // we're ready.

            // Only emit the event on editable subtitles. We don't want to initialize
            // Popcorn subtitles for the non-editable set.
            if ($scope.$parent.isEditable) {
                $scope.$root.$emit('subtitle-ready', $scope);
            }
        });
    };
    var VideoTitleController = function($scope, SubtitleListFinder) {

        // Once the working subtitles have been fetched, set the title and description.
        $scope.$root.$on('subtitles-fetched', function() {

            // Reference the actual scope in the template so we can get automatic binding
            // on the title and description.
            $scope.workingSubtitles = SubtitleListFinder.get('working-subtitle-set').scope;

        });

    };

    root.LanguageSelectorController = LanguageSelectorController;
    root.SaveSessionController = SaveSessionController;
    root.SubtitleListController = SubtitleListController;
    root.SubtitleListHelperController = SubtitleListHelperController;
    root.SubtitleListItemController = SubtitleListItemController;
    root.VideoTitleController = VideoTitleController;

}).call(this);
<|endoftext|>


<commit_before>var pkg = require('../package');
var config = require('../config');
var logger = require("../logger/logger");
var wrap = require('co-express');

var userHelper = require('../services/userHelper');
var messageHelper = require('../services/messageHelper');

var mongoose = require('../config/db.js').mongoose;
var user = mongoose.model('User', require('../models/user'));

module.exports = function(app, passport) {
    app.get('/profile/messages',
        wrap(function*(req, res, next) {
            if (userHelper.auth(req, res, app.locals.site)) {
                var messages = {};
                req.user.isMain = true;
                req = userHelper.processUser(req);

                messages.systemMessages = yield messageHelper.getSystemMessages(req.user._id, req.user.isAdmin);
                messages.userMessages = yield messageHelper.getUserMessages(req.user._id, req.user.isAdmin);

                if (!messages) messages = {};

                res.render('messages/user-messages', { site: app.locals.site, user: req.user, messages: messages, req: req });
            }
        })
    );

    app.post('/user/:userId/message', function(req, res, next) {
        if (userHelper.auth(req, res, app.locals.site)) {
            req.user.isMain = true;
            req = userHelper.processUser(req);

        }
    });

    app.post('/messages/admin', function(req, res, next) {
        if (userHelper.auth(req, res, app.locals.site)) {
            req.user.isMain = true;
            req = userHelper.processUser(req);

        }
    });
}
<commit_msg>made messages routes<commit_after>var pkg = require('../package');
var config = require('../config');
var logger = require("../logger/logger");
var wrap = require('co-express');

var userHelper = require('../services/userHelper');
var messageHelper = require('../services/messageHelper');

var mongoose = require('../config/db.js').mongoose;
var user = mongoose.model('User', require('../models/user'));

module.exports = function(app, passport) {
    app.get('/profile/messages',
        wrap(function*(req, res, next) {
            if (userHelper.auth(req, res, app.locals.site)) {
                var messages = {};
                req.user.isMain = true;
                req = userHelper.processUser(req);

                messages.systemMessages = yield messageHelper.getSystemMessages(req.user._id, req.user.isAdmin);
                messages.userMessages = yield messageHelper.getUserMessages(req.user._id, req.user.isAdmin);

                if (!messages) messages = {};

                res.render('messages/user-messages', { site: app.locals.site, user: req.user, messages: messages, req: req });
            }
        })
    );

    app.post('/user/:userId/message', function(req, res, next) {
        if (userHelper.auth(req, res, app.locals.site)) {
            req.user.isMain = true;
            req = userHelper.processUser(req);

            var iUserMessage = new userMessage({
                message: req.body.message,
                date: req.body.date,
                priority: req.body.priority,
                adminId: req.body.adminId,
                fromUserId: req.body.fromUserId,
                toUserId: req.body.toUserId,
                bookId: req.body.bookId,
                transactionId: req.body.transactionId
            });
            iUserMessage.save();

            logger.warn("created user message");

            req.flash('success', "created message to user , " + req.body.toUserId);
            res.redirect(req.session.returnTo || '/');
        }
    });

    app.post('/messages/systemMessage', function(req, res, next) {
        if (userHelper.auth(req, res, app.locals.site)) {
            req.user.isMain = true;
            req = userHelper.processUser(req);

            var iSystemMessage = new systemMessage({
                message: req.body.message,
                date: req.body.date,
                priority: req.body.priority,
                adminId: req.body.adminId
            });
            iSystemMessage.save();

            logger.warn("created system message");

            req.flash('success', "created system message");
            res.redirect(req.session.returnTo || '/');
        }
    });
}
<|endoftext|>


<commit_before>/* global Mocha require */
/* eslint-disable no-unused-vars */
const expect = require('referee').expect; // use require, so babel won't change names!
const assert = require('assert'); // use require, so babel won't change names!
import should from 'should';
import * as hamjest from 'hamjest';
/* eslint-enable no-unused-vars */

import {transform} from '@babel/core'; // the es6 transpiler
import babelPresetEnv from '@babel/preset-env';
import 'babel-polyfill';
import RuntimeError from '../runtime-error';

const global = () => new Function('return this;')();

const transpileToEs5Code = (sourceCode) => {
  try {
    return transform(sourceCode, {presets: [babelPresetEnv], babelrc: false}).code;
  } catch (e) {
    const hint = `Syntax or ES6 (babeljs) transpile error
(This transpile error doesn't mean that the web app is broken :))

    `;
    document.getElementById('errorOutput').innerHTML = hint + e;
  }
  return null;
};

const resetMochaEnvironment = () => {
  document.getElementById('mocha').innerHTML = '';
  const mocha = new Mocha({reporter: 'html', ui: 'bdd'});
  mocha.suite.emit('pre-require', global(), null, mocha);
  return mocha;
};

const state = {
  sourceCode: '',
  transpileToEs5: true,
};
const consumeMessage = (messageData) => {
  if (messageData.source === messageData.target) {
    // ignore messages sent to itself
    return;
  }
  const sender = messageData.source;
  const receivedData = messageData.data;
  if (receivedData.sourceCode) {
    state.sourceCode = receivedData.sourceCode;
  } else if ('transpileToEs5' in receivedData) {
    state.transpileToEs5 = receivedData.transpileToEs5;
  }
  const mocha = resetMochaEnvironment.call(this);
  runSpecs(state);
  runMochaAndReportStats(mocha, sender);
};

const emptyErrorPane = () => {
  document.getElementById('errorOutput').innerHTML = '';
};
const fillErrorPaneWith = (text) => {
  document.getElementById('errorOutput').innerHTML = text;
};

const runSpecDefaultDeps = {
  emptyErrorPane,
  transpileToEs5Code,
  fillErrorPaneWith,
};
const runSpecs = (state, deps = runSpecDefaultDeps) => {
  // This calls describe, it, etc. and "fills"
  // the test runner suites which are executed later in `mocha.run()`.
  deps.emptyErrorPane();
  const codeToRun = state.transpileToEs5 === false ? state.sourceCode : deps.transpileToEs5Code(state);
  if (codeToRun) {
    try {
      eval(codeToRun); // eslint-disable-line no-eval
    } catch (e) {
      const errorMessage = `Runtime error\n\n${e}\n\n${RuntimeError.prettyPrint(e.stack, codeToRun)}`;
      deps.fillErrorPaneWith(errorMessage);
    }
  }
};

const runMochaAndReportStats = (mocha, sender) => {
  // Let mocha run and report the stats back to the actual sender.
  mocha.checkLeaks();
  const runner = mocha.run(() => {}); // if there is no callback given mocha will fail and not work again :(
  function onRan() {
    const stats = runner.stats;
    sender.postMessage(stats, '*');
  }
  runner.on('end', onRan);
};

module.exports = {
  forTesting: {transpileToEs5Code, runSpecs},
};

if (global().addEventListener) global().addEventListener('message', consumeMessage, false);
<commit_msg>Make the site work again, forgot a prop access. grrr<commit_after>/* global Mocha require */
/* eslint-disable no-unused-vars */
const expect = require('referee').expect; // use require, so babel won't change names!
const assert = require('assert'); // use require, so babel won't change names!
import should from 'should';
import * as hamjest from 'hamjest';
/* eslint-enable no-unused-vars */

import {transform} from '@babel/core'; // the es6 transpiler
import babelPresetEnv from '@babel/preset-env';
import 'babel-polyfill';
import RuntimeError from '../runtime-error';

const global = () => new Function('return this;')();

const transpileToEs5Code = (sourceCode) => {
  try {
    return transform(sourceCode, {presets: [babelPresetEnv], babelrc: false}).code;
  } catch (e) {
    const hint = `Syntax or ES6 (babeljs) transpile error
(This transpile error doesn't mean that the web app is broken :))

    `;
    document.getElementById('errorOutput').innerHTML = hint + e;
  }
  return null;
};

const resetMochaEnvironment = () => {
  document.getElementById('mocha').innerHTML = '';
  const mocha = new Mocha({reporter: 'html', ui: 'bdd'});
  mocha.suite.emit('pre-require', global(), null, mocha);
  return mocha;
};

const state = {
  sourceCode: '',
  transpileToEs5: true,
};
const consumeMessage = (messageData) => {
  if (messageData.source === messageData.target) {
    // ignore messages sent to itself
    return;
  }
  const sender = messageData.source;
  const receivedData = messageData.data;
  if (receivedData.sourceCode) {
    state.sourceCode = receivedData.sourceCode;
  } else if ('transpileToEs5' in receivedData) {
    state.transpileToEs5 = receivedData.transpileToEs5;
  }
  const mocha = resetMochaEnvironment.call(this);
  runSpecs(state);
  runMochaAndReportStats(mocha, sender);
};

const emptyErrorPane = () => {
  document.getElementById('errorOutput').innerHTML = '';
};
const fillErrorPaneWith = (text) => {
  document.getElementById('errorOutput').innerHTML = text;
};

const runSpecDefaultDeps = {
  emptyErrorPane,
  transpileToEs5Code,
  fillErrorPaneWith,
};
const runSpecs = (state, deps = runSpecDefaultDeps) => {
  // This calls describe, it, etc. and "fills"
  // the test runner suites which are executed later in `mocha.run()`.
  deps.emptyErrorPane();
  const codeToRun = state.transpileToEs5 === false ? state.sourceCode : deps.transpileToEs5Code(state.sourceCode);
  if (codeToRun) {
    try {
      eval(codeToRun); // eslint-disable-line no-eval
    } catch (e) {
      const errorMessage = `Runtime error\n\n${e}\n\n${RuntimeError.prettyPrint(e.stack, codeToRun)}`;
      deps.fillErrorPaneWith(errorMessage);
    }
  }
};

const runMochaAndReportStats = (mocha, sender) => {
  // Let mocha run and report the stats back to the actual sender.
  mocha.checkLeaks();
  const runner = mocha.run(() => {}); // if there is no callback given mocha will fail and not work again :(
  function onRan() {
    const stats = runner.stats;
    sender.postMessage(stats, '*');
  }
  runner.on('end', onRan);
};

module.exports = {
  forTesting: {transpileToEs5Code, runSpecs},
};

if (global().addEventListener) global().addEventListener('message', consumeMessage, false);
<|endoftext|>


<commit_before>function ddg_spice_movie (api_result) {
    "use strict";

    if (api_result.total === 0) {
        return;
    }

    var ignore = ["movie", "film", "rotten", "rating", "rt", "tomatoes", "release date"];
    var result, max_score = 0;

    // Assign a ranking value for the movie. This isn't a complete sorting value though
    // also we are blindling assuming these values exist
    var score = function(m) {
        var s = m.ratings.critics_score * m.ratings.audience_score;
        if (s > max_score) max_score = s;
        // If any above are undefined, s is undefined.
        return s;
    };

    // returns the more relevant of the two movies
    var better = function(currentbest, next) {
        // If score() returns undefined, this is false, so we're still OK.
        return (score(next) > score(currentbest) &&
                (next.year > currentbest.year) &&
                DDG.isRelevant(next.title, ignore)) ? next : currentbest;
    };

    result = DDG_bestResult(api_result.movies, better);

    // Favor the first result if the max score is within 1% of the score for the first result.
    if (result !== api_result.movies[0] && Math.abs(score(api_result.movies[0]) - max_score) / max_score < 0.1) {
        result = api_result.movies[0];
    }

    // Check if the movie that we have is relevant enough.
    if(!DDG.isRelevant(result.title, ignore)) {
        return;
    }

    var checkYear = function(year) {
        if(year) {
            return " (" + year + ")";
        }
        return "";
    };

    if ((result.synopsis && result.synopsis.length) ||
        (result.critics_consensus && result.critics_consensus.length)) {
        result.hasContent = true;
    }

    var data = api_result.movies.map(function(m){
        m.rating = Math.round(m.ratings.critics_score / 20);
        return m;
    });

    var searchTerm = rqd.replace(new RegExp(ignore.join('|'),'i'),'').trim();

    Spice.add({
        id: 'movie',
        name: 'Movies',

        data: data,

        meta: {
            sourceName: 'Rotten Tomatoes',
            sourceUrl: 'http://rottentomatoes.com/search/?search=' + searchTerm,
            sourceIcon: true,
            count: api_result.movies.length,
            itemType: 'Movies'
        },

        templates: {
            item: 'movie_item',
        }
    });
}

/*
 * rating_adjective
 *
 * help make the description of the movie gramatically correct
 * used in reference to the rating of the movie, as in
 *   'an' R rated movie, or
 *   'a'  PG rated movie
 */
Handlebars.registerHelper("rating_adjective", function() {
    "use strict";

    return (this.mpaa_rating === "R" ||
            this.mpaa_rating === "NC-17" ||
            this.mpaa_rating === "Unrated") ?  "an" :"a";
});

/* star rating */
Handlebars.registerHelper("star_rating", function(score) {
    "use strict";

    var r = (score / 20) - 1;
    var s = "";

    if (r > 0) {
        for (var i = 0; i < r; i++) {
            s += "★";
        }
    }

    if (s.length === 0) {
        s = "0 Stars";
    }

    return s;
});
<commit_msg>movie.js: initial port to bttf<commit_after>(function(env) {
    env.ddg_spice_movie = function(api_result) {
	console.log(api_result);
    };
}(this));

// function ddg_spice_movie (api_result) {
//     "use strict";

//     if (api_result.total === 0) {
//         return;
//     }

//     var ignore = ["movie", "film", "rotten", "rating", "rt", "tomatoes", "release date"];
//     var result, max_score = 0;

//     // Assign a ranking value for the movie. This isn't a complete sorting value though
//     // also we are blindling assuming these values exist
//     var score = function(m) {
//         var s = m.ratings.critics_score * m.ratings.audience_score;
//         if (s > max_score) max_score = s;
//         // If any above are undefined, s is undefined.
//         return s;
//     };

//     // returns the more relevant of the two movies
//     var better = function(currentbest, next) {
//         // If score() returns undefined, this is false, so we're still OK.
//         return (score(next) > score(currentbest) &&
//                 (next.year > currentbest.year) &&
//                 DDG.isRelevant(next.title, ignore)) ? next : currentbest;
//     };

//     result = DDG_bestResult(api_result.movies, better);

//     // Favor the first result if the max score is within 1% of the score for the first result.
//     if (result !== api_result.movies[0] && Math.abs(score(api_result.movies[0]) - max_score) / max_score < 0.1) {
//         result = api_result.movies[0];
//     }

//     // Check if the movie that we have is relevant enough.
//     if(!DDG.isRelevant(result.title, ignore)) {
//         return;
//     }

//     var checkYear = function(year) {
//         if(year) {
//             return " (" + year + ")";
//         }
//         return "";
//     };

//     if ((result.synopsis && result.synopsis.length) ||
//         (result.critics_consensus && result.critics_consensus.length)) {
//         result.hasContent = true;
//     }

//     var data = api_result.movies.map(function(m){
//         m.rating = Math.round(m.ratings.critics_score / 20);
//         return m;
//     });

//     var searchTerm = rqd.replace(new RegExp(ignore.join('|'),'i'),'').trim();

//     Spice.add({
//         id: 'movie',
//         name: 'Movies',

//         data: data,

//         meta: {
//             sourceName: 'Rotten Tomatoes',
//             sourceUrl: 'http://rottentomatoes.com/search/?search=' + searchTerm,
//             sourceIcon: true,
//             count: api_result.movies.length,
//             itemType: 'Movies'
//         },

//         templates: {
//             item: 'movie_item',
//         }
//     });
// }

// /*
//  * rating_adjective
//  *
//  * help make the description of the movie gramatically correct
//  * used in reference to the rating of the movie, as in
//  *   'an' R rated movie, or
//  *   'a'  PG rated movie
//  */
// Handlebars.registerHelper("rating_adjective", function() {
//     "use strict";

//     return (this.mpaa_rating === "R" ||
//             this.mpaa_rating === "NC-17" ||
//             this.mpaa_rating === "Unrated") ?  "an" :"a";
// });

// /* star rating */
// Handlebars.registerHelper("star_rating", function(score) {
//     "use strict";

//     var r = (score / 20) - 1;
//     var s = "";

//     if (r > 0) {
//         for (var i = 0; i < r; i++) {
//             s += "★";
//         }
//     }

//     if (s.length === 0) {
//         s = "0 Stars";
//     }

//     return s;
// });

<|endoftext|>


<commit_before>'use strict';

const debug = require('ghost-ignition').debug('importer:base'),
    _ = require('lodash'),
    Promise = require('bluebird'),
    ObjectId = require('bson-objectid'),
    common = require('../../../../lib/common'),
    sequence = require('../../../../lib/promise/sequence'),
    models = require('../../../../models');

class Base {
    constructor(allDataFromFile, options) {
        this.options = options;
        this.modelName = options.modelName;

        this.problems = [];

        this.errorConfig = {
            allowDuplicates: true,
            returnDuplicates: true,
            showNotFoundWarning: true
        };

        this.legacyKeys = {};
        this.legacyMapper = (item) => {
            return _.mapKeys(item, (value, key) => {
                return this.legacyKeys[key] || key;
            });
        };

        this.dataKeyToImport = options.dataKeyToImport;
        this.dataToImport = _.cloneDeep(allDataFromFile[this.dataKeyToImport] || []);

        this.importedDataToReturn = [];
        this.importedData = [];

        this.requiredFromFile = {};
        this.requiredImportedData = {};
        this.requiredExistingData = {};

        if (!this.options.requiredImportedData) {
            this.options.requiredImportedData = ['users'];
        } else {
            this.options.requiredImportedData.push('users');
        }

        if (!this.options.requiredExistingData) {
            this.options.requiredExistingData = ['users'];
        } else {
            this.options.requiredExistingData.push('users');
        }

        if (!this.options.requiredFromFile) {
            this.options.requiredFromFile = ['users'];
        } else {
            this.options.requiredFromFile.push('users');
        }

        _.each(this.options.requiredFromFile, (key) => {
            this.requiredFromFile[key] = _.cloneDeep(allDataFromFile[key]);
        });
    }

    /**
     * Never ever import these attributes!
     */
    stripProperties(properties) {
        _.each(this.dataToImport, (obj) => {
            _.each(properties, (property) => {
                delete obj[property];
            });
        });
    }

    /**
     * Clean invalid values.
     */
    sanitizeValues() {
        _.each(this.dataToImport, (obj) => {
            _.each(_.pick(obj, ['updated_at', 'created_at', 'published_at']), (value, key) => {
                let temporaryDate = new Date(value);

                if (isNaN(temporaryDate)) {
                    this.problems.push({
                        message: 'Date is in a wrong format and invalid. It was replaced with the current timestamp.',
                        help: this.modelName,
                        context: JSON.stringify(obj)
                    });

                    obj[key] = new Date().toISOString();
                }
            });
        });
    }

    generateIdentifier() {
        _.each(this.dataToImport, (obj) => {
            obj.id = ObjectId.generate();
        });
    }

    fetchExisting() {
        return Promise.resolve();
    }

    beforeImport() {
        this.stripProperties(['id']);
        this.sanitizeValues();
        this.generateIdentifier();
        return Promise.resolve();
    }

    handleError(errs, obj) {
        let errorsToReject = [], problems = [];

        // CASE: validation errors, see models/base/events.js onValidate
        if (!_.isArray(errs)) {
            errs = [errs];
        }

        _.each(errs, (err) => {
            if (err.code && err.message.toLowerCase().indexOf('unique') !== -1) {
                if (this.errorConfig.allowDuplicates) {
                    if (this.errorConfig.returnDuplicates) {
                        problems.push({
                            message: 'Entry was not imported and ignored. Detected duplicated entry.',
                            help: this.modelName,
                            context: JSON.stringify(obj),
                            err: err
                        });
                    }
                } else {
                    errorsToReject.push(new common.errors.DataImportError({
                        message: 'Detected duplicated entry.',
                        help: this.modelName,
                        context: JSON.stringify(obj),
                        err: err
                    }));
                }
            } else if (err instanceof common.errors.NotFoundError) {
                if (this.errorConfig.showNotFoundWarning) {
                    problems.push({
                        message: 'Entry was not imported and ignored. Could not find entry.',
                        help: this.modelName,
                        context: JSON.stringify(obj),
                        err: err
                    });
                }
            } else {
                if (!common.errors.utils.isIgnitionError(err)) {
                    err = new common.errors.DataImportError({
                        message: err.message,
                        context: JSON.stringify(obj),
                        help: this.modelName,
                        errorType: err.errorType,
                        err: err
                    });
                } else {
                    err.context = JSON.stringify(obj);
                }

                errorsToReject.push(err);
            }
        });

        if (!errorsToReject.length) {
            this.problems = this.problems.concat(problems);
            debug('detected problem/warning', problems);

            return Promise.resolve();
        }

        debug('err', errorsToReject, obj);
        return Promise.reject(errorsToReject);
    }

    /**
     * Data is now prepared. Last step is to replace identifiers.
     *
     * `dataToImport`: the objects to import (contain the new ID already)
     * `requiredExistingData`: the importer allows you to ask for existing database objects
     * `requiredFromFile`: the importer allows you to ask for data from the file
     * `requiredImportedData`: the importer allows you to ask for already imported data
     */
    replaceIdentifiers() {
        const ownerUserId = _.find(this.requiredExistingData.users, (user) => {
            if (user.roles[0].name === 'Owner') {
                return true;
            }
        }).id;

        let userReferenceProblems = {};

        const handleObject = (obj, key) => {
            if (!obj.hasOwnProperty(key)) {
                return;
            }

            // CASE: you import null, fallback to owner
            if (!obj[key]) {
                if (!userReferenceProblems[obj.id]) {
                    userReferenceProblems[obj.id] = {obj: obj, keys: []};
                }

                userReferenceProblems[obj.id].keys.push(key);
                obj[key] = ownerUserId;
                return;
            }

            // CASE: first match the user reference with in the imported file
            let userFromFile = _.find(this.requiredFromFile.users, {id: obj[key]});

            if (!userFromFile) {
                // CASE: if user does not exist in file, try to lookup the existing db users
                let existingUser = _.find(this.requiredExistingData.users, {id: obj[key].toString()});

                // CASE: fallback to owner
                if (!existingUser) {
                    if (!userReferenceProblems[obj.id]) {
                        userReferenceProblems[obj.id] = {obj: obj, keys: []};
                    }

                    userReferenceProblems[obj.id].keys.push(key);

                    obj[key] = ownerUserId;
                    return;
                } else {
                    // CASE: user exists in the database, ID is correct, skip
                    return;
                }
            }

            // CASE: users table is the first data we insert. we have no access to the imported data yet
            // Result: `this.requiredImportedData.users` will be empty.
            // We already generate identifiers for each object in the importer layer. Accessible via `dataToImport`.
            if (this.modelName === 'User' && !this.requiredImportedData.users.length) {
                let userToImport = _.find(this.dataToImport, {slug: userFromFile.slug});

                if (userToImport) {
                    obj[key] = userToImport.id;
                    return;
                } else {
                    // CASE: unknown
                    return;
                }
            }

            // CASE: user exists in the file, let's find his db id
            // NOTE: lookup by email, because slug can change on insert
            let importedUser = _.find(this.requiredImportedData.users, {email: userFromFile.email});

            // CASE: found. let's assign the new ID
            if (importedUser) {
                obj[key] = importedUser.id;
                return;
            }

            // CASE: user was not imported, let's figure out if the user exists in the database
            let existingUser = _.find(this.requiredExistingData.users, {slug: userFromFile.slug});

            if (!existingUser) {
                // CASE: let's try by ID
                existingUser = _.find(this.requiredExistingData.users, {id: userFromFile.id.toString()});

                if (!existingUser) {
                    if (!userReferenceProblems[obj.id]) {
                        userReferenceProblems[obj.id] = {obj: obj, keys: []};
                    }

                    userReferenceProblems[obj.id].keys.push(key);

                    obj[key] = ownerUserId;
                }
            } else {
                obj[key] = existingUser.id;
            }
        };

        // Iterate over all possible user relations
        _.each(this.dataToImport, (obj) => {
            _.each([
                'author_id',
                'published_by',
                'created_by',
                'updated_by'
            ], (key) => {
                return handleObject(obj, key);
            });
        });

        _.each(userReferenceProblems, (entry) => {
            this.problems.push({
                message: 'Entry was imported, but we were not able to resolve the following user references: ' +
                entry.keys.join(', ') + '. The user does not exist, fallback to owner user.',
                help: this.modelName,
                context: JSON.stringify(entry.obj)
            });
        });
    }

    doImport(options, importOptions) {
        debug('doImport', this.modelName, this.dataToImport.length);

        let ops = [];

        _.each(this.dataToImport, (obj) => {
            ops.push(() => {
                return models[this.modelName].add(obj, options)
                    .then((importedModel) => {
                        obj.model = {
                            id: importedModel.id
                        };

                        if (importOptions.returnImportedData) {
                            this.importedDataToReturn.push(importedModel.toJSON());
                        }

                        // for identifier lookup
                        this.importedData.push({
                            id: importedModel.id,
                            slug: importedModel.get('slug'),
                            email: importedModel.get('email')
                        });

                        return importedModel;
                    })
                    .catch((err) => {
                        return this.handleError(err, obj);
                    })
                    .reflect();
            });
        });

        /**
         * NOTE: Do not run with Promise.all in this case. With a large import file, we run an enormous
         *       amount of queries in parallel. Node will very fast eat lot's of memory, because all queries start
         *       at the same time, but memory can only be released if the query finished.
         *
         *       Promise.map(.., {concurrency: Int}) was not really improving the end performance for me.
         */
        return sequence(ops);
    }
}

module.exports = Base;
<commit_msg>Show correct importer context objects<commit_after>'use strict';

const debug = require('ghost-ignition').debug('importer:base'),
    _ = require('lodash'),
    Promise = require('bluebird'),
    ObjectId = require('bson-objectid'),
    common = require('../../../../lib/common'),
    sequence = require('../../../../lib/promise/sequence'),
    models = require('../../../../models');

class Base {
    constructor(allDataFromFile, options) {
        this.options = options;
        this.modelName = options.modelName;

        this.problems = [];

        this.errorConfig = {
            allowDuplicates: true,
            returnDuplicates: true,
            showNotFoundWarning: true
        };

        this.legacyKeys = {};
        this.legacyMapper = (item) => {
            return _.mapKeys(item, (value, key) => {
                return this.legacyKeys[key] || key;
            });
        };

        this.dataKeyToImport = options.dataKeyToImport;
        this.dataToImport = _.cloneDeep(allDataFromFile[this.dataKeyToImport] || []);

        this.importedDataToReturn = [];
        this.importedData = [];

        this.requiredFromFile = {};
        this.requiredImportedData = {};
        this.requiredExistingData = {};

        if (!this.options.requiredImportedData) {
            this.options.requiredImportedData = ['users'];
        } else {
            this.options.requiredImportedData.push('users');
        }

        if (!this.options.requiredExistingData) {
            this.options.requiredExistingData = ['users'];
        } else {
            this.options.requiredExistingData.push('users');
        }

        if (!this.options.requiredFromFile) {
            this.options.requiredFromFile = ['users'];
        } else {
            this.options.requiredFromFile.push('users');
        }

        _.each(this.options.requiredFromFile, (key) => {
            this.requiredFromFile[key] = _.cloneDeep(allDataFromFile[key]);
        });
    }

    /**
     * Never ever import these attributes!
     */
    stripProperties(properties) {
        _.each(this.dataToImport, (obj) => {
            _.each(properties, (property) => {
                delete obj[property];
            });
        });
    }

    /**
     * Clean invalid values.
     */
    sanitizeValues() {
        _.each(this.dataToImport, (obj) => {
            _.each(_.pick(obj, ['updated_at', 'created_at', 'published_at']), (value, key) => {
                let temporaryDate = new Date(value);

                if (isNaN(temporaryDate)) {
                    this.problems.push({
                        message: 'Date is in a wrong format and invalid. It was replaced with the current timestamp.',
                        help: this.modelName,
                        context: JSON.stringify(obj)
                    });

                    obj[key] = new Date().toISOString();
                }
            });
        });
    }

    generateIdentifier() {
        _.each(this.dataToImport, (obj) => {
            obj.id = ObjectId.generate();
        });
    }

    fetchExisting() {
        return Promise.resolve();
    }

    beforeImport() {
        this.stripProperties(['id']);
        this.sanitizeValues();
        this.generateIdentifier();
        return Promise.resolve();
    }

    handleError(errs, obj) {
        let errorsToReject = [], problems = [];

        // CASE: validation errors, see models/base/events.js onValidate
        if (!_.isArray(errs)) {
            errs = [errs];
        }

        _.each(errs, (err) => {
            if (err.code && err.message.toLowerCase().indexOf('unique') !== -1) {
                if (this.errorConfig.allowDuplicates) {
                    if (this.errorConfig.returnDuplicates) {
                        problems.push({
                            message: 'Entry was not imported and ignored. Detected duplicated entry.',
                            help: this.modelName,
                            context: JSON.stringify(obj),
                            err: err
                        });
                    }
                } else {
                    errorsToReject.push(new common.errors.DataImportError({
                        message: 'Detected duplicated entry.',
                        help: this.modelName,
                        context: JSON.stringify(obj),
                        err: err
                    }));
                }
            } else if (err instanceof common.errors.NotFoundError) {
                if (this.errorConfig.showNotFoundWarning) {
                    problems.push({
                        message: 'Entry was not imported and ignored. Could not find entry.',
                        help: this.modelName,
                        context: JSON.stringify(obj),
                        err: err
                    });
                }
            } else {
                if (!common.errors.utils.isIgnitionError(err)) {
                    err = new common.errors.DataImportError({
                        message: err.message,
                        context: JSON.stringify(obj),
                        help: this.modelName,
                        errorType: err.errorType,
                        err: err
                    });
                } else {
                    err.context = JSON.stringify(obj);
                }

                errorsToReject.push(err);
            }
        });

        if (!errorsToReject.length) {
            this.problems = this.problems.concat(problems);
            debug('detected problem/warning', problems);

            return Promise.resolve();
        }

        debug('err', errorsToReject, obj);
        return Promise.reject(errorsToReject);
    }

    /**
     * Data is now prepared. Last step is to replace identifiers.
     *
     * `dataToImport`: the objects to import (contain the new ID already)
     * `requiredExistingData`: the importer allows you to ask for existing database objects
     * `requiredFromFile`: the importer allows you to ask for data from the file
     * `requiredImportedData`: the importer allows you to ask for already imported data
     */
    replaceIdentifiers() {
        const ownerUserId = _.find(this.requiredExistingData.users, (user) => {
            if (user.roles[0].name === 'Owner') {
                return true;
            }
        }).id;

        let userReferenceProblems = {};

        const handleObject = (obj, key) => {
            if (!obj.hasOwnProperty(key)) {
                return;
            }

            // CASE: you import null, fallback to owner
            if (!obj[key]) {
                if (!userReferenceProblems[obj.id]) {
                    userReferenceProblems[obj.id] = {obj: _.cloneDeep(obj), keys: []};
                }

                userReferenceProblems[obj.id].keys.push(key);
                obj[key] = ownerUserId;
                return;
            }

            // CASE: first match the user reference with in the imported file
            let userFromFile = _.find(this.requiredFromFile.users, {id: obj[key]});

            if (!userFromFile) {
                // CASE: if user does not exist in file, try to lookup the existing db users
                let existingUser = _.find(this.requiredExistingData.users, {id: obj[key].toString()});

                // CASE: fallback to owner
                if (!existingUser) {
                    if (!userReferenceProblems[obj.id]) {
                        userReferenceProblems[obj.id] = {obj: _.cloneDeep(obj), keys: []};
                    }

                    userReferenceProblems[obj.id].keys.push(key);

                    obj[key] = ownerUserId;
                    return;
                } else {
                    // CASE: user exists in the database, ID is correct, skip
                    return;
                }
            }

            // CASE: users table is the first data we insert. we have no access to the imported data yet
            // Result: `this.requiredImportedData.users` will be empty.
            // We already generate identifiers for each object in the importer layer. Accessible via `dataToImport`.
            if (this.modelName === 'User' && !this.requiredImportedData.users.length) {
                let userToImport = _.find(this.dataToImport, {slug: userFromFile.slug});

                if (userToImport) {
                    obj[key] = userToImport.id;
                    return;
                } else {
                    // CASE: unknown
                    return;
                }
            }

            // CASE: user exists in the file, let's find his db id
            // NOTE: lookup by email, because slug can change on insert
            let importedUser = _.find(this.requiredImportedData.users, {email: userFromFile.email});

            // CASE: found. let's assign the new ID
            if (importedUser) {
                obj[key] = importedUser.id;
                return;
            }

            // CASE: user was not imported, let's figure out if the user exists in the database
            let existingUser = _.find(this.requiredExistingData.users, {slug: userFromFile.slug});

            if (!existingUser) {
                // CASE: let's try by ID
                existingUser = _.find(this.requiredExistingData.users, {id: userFromFile.id.toString()});

                if (!existingUser) {
                    if (!userReferenceProblems[obj.id]) {
                        userReferenceProblems[obj.id] = {obj: _.cloneDeep(obj), keys: []};
                    }

                    userReferenceProblems[obj.id].keys.push(key);

                    obj[key] = ownerUserId;
                }
            } else {
                obj[key] = existingUser.id;
            }
        };

        // Iterate over all possible user relations
        _.each(this.dataToImport, (obj) => {
            _.each([
                'author_id',
                'published_by',
                'created_by',
                'updated_by'
            ], (key) => {
                return handleObject(obj, key);
            });
        });

        _.each(userReferenceProblems, (entry) => {
            this.problems.push({
                message: 'Entry was imported, but we were not able to resolve the following user references: ' +
                entry.keys.join(', ') + '. The user does not exist, fallback to owner user.',
                help: this.modelName,
                context: JSON.stringify(entry.obj)
            });
        });
    }

    doImport(options, importOptions) {
        debug('doImport', this.modelName, this.dataToImport.length);

        let ops = [];

        _.each(this.dataToImport, (obj) => {
            ops.push(() => {
                return models[this.modelName].add(obj, options)
                    .then((importedModel) => {
                        obj.model = {
                            id: importedModel.id
                        };

                        if (importOptions.returnImportedData) {
                            this.importedDataToReturn.push(importedModel.toJSON());
                        }

                        // for identifier lookup
                        this.importedData.push({
                            id: importedModel.id,
                            slug: importedModel.get('slug'),
                            email: importedModel.get('email')
                        });

                        return importedModel;
                    })
                    .catch((err) => {
                        return this.handleError(err, obj);
                    })
                    .reflect();
            });
        });

        /**
         * NOTE: Do not run with Promise.all in this case. With a large import file, we run an enormous
         *       amount of queries in parallel. Node will very fast eat lot's of memory, because all queries start
         *       at the same time, but memory can only be released if the query finished.
         *
         *       Promise.map(.., {concurrency: Int}) was not really improving the end performance for me.
         */
        return sequence(ops);
    }
}

module.exports = Base;
<|endoftext|>


<commit_before>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe(FILL_ME_IN); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(FILL_ME_IN);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(FILL_ME_IN);
    expect(multiTypeArray[2]).toBe(FILL_ME_IN);
    expect(multiTypeArray[3]()).toBe(FILL_ME_IN);
    expect(multiTypeArray[4].value1).toBe(FILL_ME_IN);
    expect(multiTypeArray[4]["value2"]).toBe(FILL_ME_IN);
    expect(multiTypeArray[5][0]).toBe(FILL_ME_IN);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, FILL_ME_IN]);

    array.push(3);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(FILL_ME_IN);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(FILL_ME_IN);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
    expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
    expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>fixed failing tests in AboutArrays.js<commit_after>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1, 2, 3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut", "butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and", "jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(["jelly"]);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe("changed in function");

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe("changed in assignedArray");

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual([1, 2, 3]);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(3);
    expect(array).toEqual([1, 2]);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual([3, 1, 2]);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(3);
    expect(array).toEqual([1, 2]);
  });
});
<|endoftext|>