<commit_before>/**
 * TaskFeedController
 * @namespace crowdsource.template.controllers
 * @author dmorina
 */
(function () {
    'use strict';

    angular
        .module('crowdsource.template.controllers')
        .controller('TemplateController', TemplateController);

    TemplateController.$inject = ['$window', '$state', '$scope', 'Template', '$filter', '$sce', '$mdDialog'];

    /**
     * @namespace TemplateController
     */
    function TemplateController($window, $state, $scope, Template, $filter, $sce, $mdDialog) {
        var self = this;

        self.buildHtml = buildHtml;
        self.select = select;
        self.deselect = deselect;
        self.copy = copy;
        self.removeItem = removeItem;
        self.addComponent = addComponent;
        self.showTaskDesign = showTaskDesign;
        self.getIcon = getIcon;
        self.addOption = addOption;
        self.removeOption = removeOption;
        self.items_with_data = [];
        self.headers = [];
        self.getTrustedUrl = getTrustedUrl;
        self.setDataSource = setDataSource;
        self.onSort = onSort;
        self.sortConfig = {
            group: 'template_items',
            animation: 150,
            handle: '.handle',
            onSort: onSort
        };

        var idGenIndex = 0;

        self.items = _.map(self.items, function (item) {
            if (item.hasOwnProperty('isSelected')) {
                delete item.isSelected;
            }
            return item;
        });

        self.selectedItem = null;

        self.templateComponents = Template.getTemplateComponents($scope);

        function buildHtml(item) {
            var html = Template.buildHtml(item);
            return $sce.trustAsHtml(html);
        }

        function deselect(item) {
            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected') && self.selectedItem === item) {
                self.selectedItem.isSelected = false;
                self.selectedItem = null;
            }
        }

        function select(item) {
            // deselect earlier item and select this one
            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected')) {
                self.selectedItem.isSelected = false;
            }

            self.selectedItem = item;
            item.isSelected = true;
        }

        function copy(item) {
            deselect(item);
            var component = _.find(self.templateComponents, function (component) {
                return component.type == item.type
            });

            var field = angular.copy(component);
            var curId = generateId();

            field.name = 'item' + curId;
            field.aux_attributes = item.aux_attributes;

            addComponent(field);
        }

        function removeItem(item) {
            var index = self.items.indexOf(item);
            self.items.splice(index, 1);
            self.selectedItem = null;
            resetItemPosition();
            Template.deleteItem(item.id).then(
                function success(response) {

                },
                function error(response) {
                    $mdToast.showSimple('Could not delete template item.');
                }
            ).finally(function () {
            });
        }

        function resetItemPosition() {
            var i = 0;
            for (i = 0; i < self.items.length; i++) {
                self.items[i].position = i + 1;
            }
        }

        $scope.$watch('project.project', function (newValue, oldValue) {
            if (!angular.equals(newValue, oldValue) && newValue.hasOwnProperty('templates') && self.items && self.items.length == 0) {
                self.items = newValue.templates[0].template_items;
            }
            if (!angular.equals(newValue, oldValue) && newValue.hasOwnProperty('batch_files')) {
                if (newValue.batch_files.length == 1) {
                    self.headers = newValue.batch_files[0].column_headers;
                }
                else {
                    self.headers = [];
                }
            }
        }, true);
        function addComponent(component) {

            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected')) {
                self.selectedItem.isSelected = false;
            }

            var field = angular.copy(component);
            var curId = generateId();
            field.name = 'item' + curId;

            angular.extend(field, {template: $scope.project.project.templates[0].id});
            angular.extend(field, {position: self.items.length + 1});

            Template.addItem(field).then(
                function success(response) {
                    angular.extend(field, {id: response[0].id});
                    self.items.push(field);
                },
                function error(response) {
                    $mdToast.showSimple('Could not update project name.');
                }
            ).finally(function () {
            });

            //sync();
        }

        function generateId() {
            return '' + ++idGenIndex;
        }

        function generateRandomTemplateName() {
            var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            var random = _.sample(possible, 8).join('');
            return 'template_' + random;
        }

        function sync() {
            $scope.project.template = {
                name: self.templateName,
                items: self.items
            }
        }

        //Show Modal Pop-up of the Task Design Output
        function showTaskDesign(previewButton) {
            update_item_data();

            $mdDialog.show({
                template: '<md-dialog class="centered-dialog" aria-label="preview">' +
                '<md-dialog-content md-scroll-y>' +
                '
' +
                '

' +
                '<md-divider></md-divider>' +
                '

' +
                '
' +
                '<md-list class="no-decoration-list">' +
                '   <md-list-item class="template-item" ng-repeat="item in template.items_with_data">' +
                '
' +
                '
' +
                '

' +
                '
' +
                '
' +
                '   </md-list-item>' +
                '</md-list>' +
                '</md-dialog-content>' +
                '</md-dialog>',
                parent: angular.element(document.body),
                scope: $scope,
                targetEvent: previewButton,
                preserveScope: true,
                clickOutsideToClose: true
            });
        }

        function replaceAll(find, replace, str) {
            return str.replace(new RegExp(find, 'g'), replace);
        }

        function update_item_data() {
            angular.copy(self.items, self.items_with_data);
            self.items_with_data = _.map(self.items_with_data, function (obj) {

                if ($scope.project.project.metadata && $scope.project.project.batch_files[0].hasOwnProperty("column_headers")) {
                    angular.forEach($scope.project.project.batch_files[0].column_headers, function (header) {
                        var search = header.slice(1, header.length - 1);

                        obj.label = replaceAll(header, $scope.project.project.batch_files[0].firs_row[search], obj.label);
                        obj.values = replaceAll(header, $scope.project.project.batch_files[0].firs_row[search], obj.values);
                    });
                }

                // this will trigger recompiling of template
                delete obj.isSelected;

                return obj;
            });
        }

        function getIcon(item_type, index) {
            if (item_type == 'checkbox') return 'check_box_outline_blank';
            else if (item_type == 'radio') return 'radio_button_unchecked';
            else if (item_type == 'select') return index + '.';
        }

        function addOption(item) {
            var option = {
                value: 'Option ' + (item.aux_attributes.options.length + 1)
            };
            item.aux_attributes.options.push(option);
        }

        function removeOption(item, index) {
            item.aux_attributes.options.splice(index, 1);
        }

        function getTrustedUrl(url) {
            return $sce.trustAsResourceUrl(url);
        }

        function indexOfDataSource(item, data_source) {
            return item.map(function (e) {
                return e.value;
            }).indexOf(data_source);
        }

        function setDataSource(item, data_source) {
            //For options in image,audio and iframe components
            if ((!item.options || item.src) && item.question) {
                item.src = item.src || "";
                var parsed_item_src = item.src.replace(/\s+/g, ' ').trim();

                //See if the data_source has already been linked
                if(parsed_item_src.search(new RegExp("{\\s*"+data_source+"\\s*}")) > -1){
                    if(item.hasOwnProperty('src'))
                        item.src = parsed_item_src.replace(new RegExp("{\\s*"+data_source+"\\s*}","g")," ");
                }
                else{
                    if(item.hasOwnProperty('src'))
                        item.src += '{'+data_source+'}';
                }
            }
            else {
                var parsed_item_value = item.value.replace(/\s+/g, ' ').trim();

                //See if the data_source has already been linked
                if(parsed_item_value.search(new RegExp("{\\s*"+data_source+"\\s*}")) > -1){
                    if(item.hasOwnProperty('value'))
                        item.value = parsed_item_value.replace(new RegExp("{\\s*"+data_source+"\\s*}","g")," ");
                }
                else{
                    if(item.hasOwnProperty('value'))
                        item.value += '{'+data_source+'}';
                }
            }

        }

        function onSort() {
            resetItemPosition();
        }
    }

})();
<commit_msg>cleanup<commit_after>/**
 * TaskFeedController
 * @namespace crowdsource.template.controllers
 * @author dmorina
 */
(function () {
    'use strict';

    angular
        .module('crowdsource.template.controllers')
        .controller('TemplateController', TemplateController);

    TemplateController.$inject = ['$window', '$state', '$scope', 'Template', '$filter', '$sce', '$mdDialog'];

    /**
     * @namespace TemplateController
     */
    function TemplateController($window, $state, $scope, Template, $filter, $sce, $mdDialog) {
        var self = this;

        self.buildHtml = buildHtml;
        self.select = select;
        self.deselect = deselect;
        self.copy = copy;
        self.removeItem = removeItem;
        self.addComponent = addComponent;
        self.showTaskDesign = showTaskDesign;
        self.getIcon = getIcon;
        self.addOption = addOption;
        self.removeOption = removeOption;
        self.items_with_data = [];
        self.headers = [];
        self.getTrustedUrl = getTrustedUrl;
        self.setDataSource = setDataSource;
        self.onSort = onSort;
        self.sortConfig = {
            group: 'template_items',
            animation: 150,
            handle: '.handle',
            onSort: onSort
        };

        var idGenIndex = 0;

        self.items = _.map(self.items, function (item) {
            if (item.hasOwnProperty('isSelected')) {
                delete item.isSelected;
            }
            return item;
        });

        self.selectedItem = null;

        self.templateComponents = Template.getTemplateComponents($scope);

        function buildHtml(item) {
            var html = Template.buildHtml(item);
            return $sce.trustAsHtml(html);
        }

        function deselect(item) {
            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected') && self.selectedItem === item) {
                self.selectedItem.isSelected = false;
                self.selectedItem = null;
            }
        }

        function select(item) {
            // deselect earlier item and select this one
            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected')) {
                self.selectedItem.isSelected = false;
            }

            self.selectedItem = item;
            item.isSelected = true;
        }

        function copy(item) {
            deselect(item);
            var component = _.find(self.templateComponents, function (component) {
                return component.type == item.type
            });

            var field = angular.copy(component);
            var curId = generateId();

            field.name = 'item' + curId;
            field.aux_attributes = item.aux_attributes;

            addComponent(field);
        }

        function removeItem(item) {
            var index = self.items.indexOf(item);
            self.items.splice(index, 1);
            self.selectedItem = null;
            resetItemPosition();
            Template.deleteItem(item.id).then(
                function success(response) {

                },
                function error(response) {
                    $mdToast.showSimple('Could not delete template item.');
                }
            ).finally(function () {
            });
        }

        function resetItemPosition() {
            var i = 0;
            for (i = 0; i < self.items.length; i++) {
                self.items[i].position = i + 1;
            }
        }

        $scope.$watch('project.project', function (newValue, oldValue) {
            if (!angular.equals(newValue, oldValue) && newValue.hasOwnProperty('templates') && self.items && self.items.length == 0) {
                self.items = newValue.templates[0].items;
            }
            if (!angular.equals(newValue, oldValue) && newValue.hasOwnProperty('batch_files')) {
                if (newValue.batch_files.length == 1) {
                    self.headers = newValue.batch_files[0].column_headers;
                }
                else {
                    self.headers = [];
                }
            }
        }, true);
        function addComponent(component) {

            if (self.selectedItem && self.selectedItem.hasOwnProperty('isSelected')) {
                self.selectedItem.isSelected = false;
            }

            var field = angular.copy(component);
            var curId = generateId();
            field.name = 'item' + curId;

            angular.extend(field, {template: $scope.project.project.templates[0].id});
            angular.extend(field, {position: self.items.length + 1});

            Template.addItem(field).then(
                function success(response) {
                    angular.extend(field, {id: response[0].id});
                    self.items.push(field);
                },
                function error(response) {
                    $mdToast.showSimple('Could not update project name.');
                }
            ).finally(function () {
            });

            //sync();
        }

        function generateId() {
            return '' + ++idGenIndex;
        }

        function generateRandomTemplateName() {
            var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            var random = _.sample(possible, 8).join('');
            return 'template_' + random;
        }

        function sync() {
            $scope.project.template = {
                name: self.templateName,
                items: self.items
            }
        }

        //Show Modal Pop-up of the Task Design Output
        function showTaskDesign(previewButton) {
            update_item_data();

            $mdDialog.show({
                template: '<md-dialog class="centered-dialog" aria-label="preview">' +
                '<md-dialog-content md-scroll-y>' +
                '
' +
                '

' +
                '<md-divider></md-divider>' +
                '

' +
                '
' +
                '<md-list class="no-decoration-list">' +
                '   <md-list-item class="template-item" ng-repeat="item in template.items_with_data">' +
                '
' +
                '
' +
                '

' +
                '
' +
                '
' +
                '   </md-list-item>' +
                '</md-list>' +
                '</md-dialog-content>' +
                '</md-dialog>',
                parent: angular.element(document.body),
                scope: $scope,
                targetEvent: previewButton,
                preserveScope: true,
                clickOutsideToClose: true
            });
        }

        function replaceAll(find, replace, str) {
            return str.replace(new RegExp(find, 'g'), replace);
        }

        function update_item_data() {
            angular.copy(self.items, self.items_with_data);
            self.items_with_data = _.map(self.items_with_data, function (obj) {

                if ($scope.project.project.metadata && $scope.project.project.batch_files[0].hasOwnProperty("column_headers")) {
                    angular.forEach($scope.project.project.batch_files[0].column_headers, function (header) {
                        var search = header.slice(1, header.length - 1);

                        obj.label = replaceAll(header, $scope.project.project.batch_files[0].firs_row[search], obj.label);
                        obj.values = replaceAll(header, $scope.project.project.batch_files[0].firs_row[search], obj.values);
                    });
                }

                // this will trigger recompiling of template
                delete obj.isSelected;

                return obj;
            });
        }

        function getIcon(item_type, index) {
            if (item_type == 'checkbox') return 'check_box_outline_blank';
            else if (item_type == 'radio') return 'radio_button_unchecked';
            else if (item_type == 'select') return index + '.';
        }

        function addOption(item) {
            var option = {
                value: 'Option ' + (item.aux_attributes.options.length + 1)
            };
            item.aux_attributes.options.push(option);
        }

        function removeOption(item, index) {
            item.aux_attributes.options.splice(index, 1);
        }

        function getTrustedUrl(url) {
            return $sce.trustAsResourceUrl(url);
        }

        function indexOfDataSource(item, data_source) {
            return item.map(function (e) {
                return e.value;
            }).indexOf(data_source);
        }

        function setDataSource(item, data_source) {
            //For options in image,audio and iframe components
            if ((!item.options || item.src) && item.question) {
                item.src = item.src || "";
                var parsed_item_src = item.src.replace(/\s+/g, ' ').trim();

                //See if the data_source has already been linked
                if(parsed_item_src.search(new RegExp("{\\s*"+data_source+"\\s*}")) > -1){
                    if(item.hasOwnProperty('src'))
                        item.src = parsed_item_src.replace(new RegExp("{\\s*"+data_source+"\\s*}","g")," ");
                }
                else{
                    if(item.hasOwnProperty('src'))
                        item.src += '{'+data_source+'}';
                }
            }
            else {
                var parsed_item_value = item.value.replace(/\s+/g, ' ').trim();

                //See if the data_source has already been linked
                if(parsed_item_value.search(new RegExp("{\\s*"+data_source+"\\s*}")) > -1){
                    if(item.hasOwnProperty('value'))
                        item.value = parsed_item_value.replace(new RegExp("{\\s*"+data_source+"\\s*}","g")," ");
                }
                else{
                    if(item.hasOwnProperty('value'))
                        item.value += '{'+data_source+'}';
                }
            }

        }

        function onSort() {
            resetItemPosition();
        }
    }

})();
<|endoftext|>


<commit_before>import assert from 'assert';
import sinon from 'sinon';
import {
  promiseThat,
  assertThat,
  fulfilled,
  isFulfilledWith,
  allOf,
  equalTo,
  is,
  truthy,
  falsy
} from 'hamjest';

assert.called = sinon.assert.called;
assert.calledWith = sinon.assert.calledWith;

describe('', function() {

  class File {}

  class JsonFile {
    constructor(readFile, writeFile) {
      this.readFile = readFile;
      this.writeFile = writeFile;
      this.fileContent = null;
    }
    read(file) {
      this.fileContent = this.readFile(file);
      return this;
    }
    minify() {
      this.fileContent = this.fileContent.then(content => JSON.stringify(JSON.parse(content)));
      return this;
    }
    write(file) {
      return this.fileContent.then(content => this.writeFile(file, content));
    }
  }

  describe('reads the file', function() {

    const payload = {a:1};
    const beautifiedJson = JSON.stringify(payload, null, 4);
    const minifiedJson = JSON.stringify(payload);
    const file = new File();

    function readJsonFile(readFile, file) {
      return new JsonFile(readFile).read(file).minify().fileContent;
    }

    it('and minifies the JSON', function() {
      let readFile = () => Promise.resolve(beautifiedJson);

      const fileContent = readJsonFile(readFile);

      return promiseThat(fileContent, isFulfilledWith(minifiedJson));
    });

    it('from the given path', function() {
      let readFile = sinon.stub();
      readFile.returns(Promise.resolve(beautifiedJson));

      readJsonFile(readFile, file);

      assert.calledWith(readFile, file);
    });

  });

  describe('writes file content', function() {

    it('and returns a promise when done', function() {
      const fileContent = 'file content';
      const readFile = () => Promise.resolve(fileContent);
      const writeFile = sinon.stub();
      const file = new File();
      let jsonFile = new JsonFile(readFile, writeFile);

      return promiseThat(jsonFile.read().write(file), fulfilled());
    });

    it('to given path', function(done) {
      const fileContent = 'file content';
      const readFile = () => Promise.resolve(fileContent);
      const writeFile = sinon.stub();
      const file = new File();
      let jsonFile = new JsonFile(readFile, writeFile);

      //return promiseThat(jsonFile.read().write(file), allOf(fulfilled(), is(truthy(writeFile.calledWith(file, fileContent)))));

      jsonFile.read().write(file).then(() => {
        assert.calledWith(writeFile, file, fileContent);
        done();
      }).catch(() => {
        done(new Error('promise was rejected'));
      });
    });

  });

});
<commit_msg>Extract part into separate function.<commit_after>import assert from 'assert';
import sinon from 'sinon';
import {
  promiseThat,
  assertThat,
  fulfilled,
  isFulfilledWith,
  allOf,
  equalTo,
  is,
  truthy,
  falsy
} from 'hamjest';

assert.called = sinon.assert.called;
assert.calledWith = sinon.assert.calledWith;

describe('', function() {

  class File {}

  class JsonFile {
    constructor(readFile, writeFile) {
      this.readFile = readFile;
      this.writeFile = writeFile;
      this.fileContent = null;
    }
    read(file) {
      this.fileContent = this.readFile(file);
      return this;
    }
    minify() {
      const minifyJson = content => JSON.stringify(JSON.parse(content));
      this.fileContent = this.fileContent.then(minifyJson);
      return this;
    }
    write(file) {
      return this.fileContent.then(content => this.writeFile(file, content));
    }
  }

  describe('reads the file', function() {

    const payload = {a:1};
    const beautifiedJson = JSON.stringify(payload, null, 4);
    const minifiedJson = JSON.stringify(payload);
    const file = new File();

    function readJsonFile(readFile, file) {
      return new JsonFile(readFile).read(file).minify().fileContent;
    }

    it('and minifies the JSON', function() {
      let readFile = () => Promise.resolve(beautifiedJson);

      const fileContent = readJsonFile(readFile);

      return promiseThat(fileContent, isFulfilledWith(minifiedJson));
    });

    it('from the given path', function() {
      let readFile = sinon.stub();
      readFile.returns(Promise.resolve(beautifiedJson));

      readJsonFile(readFile, file);

      assert.calledWith(readFile, file);
    });

  });

  describe('writes file content', function() {

    it('and returns a promise when done', function() {
      const fileContent = 'file content';
      const readFile = () => Promise.resolve(fileContent);
      const writeFile = sinon.stub();
      const file = new File();
      let jsonFile = new JsonFile(readFile, writeFile);

      return promiseThat(jsonFile.read().write(file), fulfilled());
    });

    it('to given path', function(done) {
      const fileContent = 'file content';
      const readFile = () => Promise.resolve(fileContent);
      const writeFile = sinon.stub();
      const file = new File();
      let jsonFile = new JsonFile(readFile, writeFile);

      //return promiseThat(jsonFile.read().write(file), allOf(fulfilled(), is(truthy(writeFile.calledWith(file, fileContent)))));

      jsonFile.read().write(file).then(() => {
        assert.calledWith(writeFile, file, fileContent);
        done();
      }).catch(() => {
        done(new Error('promise was rejected'));
      });
    });

  });

});
<|endoftext|>


<commit_before><commit_msg>Create 10 Removing Disconnected Ones.js<commit_after><|endoftext|>


<commit_before>const { expect } = require('chai');
const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);

const courseMembersService = app.service('/courses/:scopeId/members');

describe('course scope members service', () => {
	it('is properly registered', () => {
		expect(courseMembersService).to.not.equal(undefined);
	});

	describe('returns all members', () => {
		it('in small courses', async () => {
			const user = await testObjects.createTestUser();
			const activeCourse = await testObjects.createTestCourse({
				userIds: [user._id],
			});
			const response = await courseMembersService.find({ route: { scopeId: activeCourse._id } });
			expect(Object.keys(response)).to.deep.equal([user._id.toString()]);
		});
	});

	afterEach(testObjects.cleanup);
});
<commit_msg>Improve tests<commit_after>const { expect } = require('chai');
const { Forbidden } = require('@feathersjs/errors');

const app = require('../../../../src/app');
const testObjects = require('../../helpers/testObjects')(app);
const { generateRequestParamsFromUser } = require('../../helpers/services/login')(app);

const courseMembersService = app.service('/courses/:scopeId/members');

describe('course scope members service', () => {
	let server;

	before((done) => {
		server = app.listen(0, done);
	});

	after((done) => {
		server.close(done);
	});

	it('is properly registered', () => {
		expect(courseMembersService).to.not.equal(undefined);
	});

	describe('in a small course', () => {
		let teacher;
		let student;
		let course;

		let teacherParams;
		let studentParams;

		before(async function before() {
			this.timeout(5000);
			teacher = await testObjects.createTestUser();
			teacherParams = await generateRequestParamsFromUser(teacher);
			student = await testObjects.createTestUser();
			studentParams = await generateRequestParamsFromUser(student);
			course = await testObjects.createTestCourse({
				teacherIds: [teacher._id],
				userIds: [student._id],
			});
		});

		after(testObjects.cleanup);

		it('returns the right members', async () => {
			const response = await courseMembersService.find({ route: { scopeId: course._id } });
			expect(Object.keys(response)).to.have.members([teacher._id.toString(), student._id.toString()]);
		});

		it('assigns the correct permissions to each userId', async () => {
			const response = await courseMembersService.find({ route: { scopeId: course._id } });
			for (const userId in response) {
				if (userId === teacher._id.toString()) {
					expect(response[userId]).to.include.members([
						'COURSE_EDIT', 'COURSE_DELETE', 'SCOPE_PERMISSIONS_VIEW',
					]);
				} else if (userId === student._id.toString()) {
					expect(response[userId]).to.include.members(['HOMEWORK_VIEW', 'COURSE_VIEW']);
					expect(response[userId]).to.not.include.members([
						'COURSE_EDIT', 'COURSE_DELETE', 'SCOPE_PERMISSIONS_VIEW',
					]);
				}
			}
		});

		it('allows access to the teacher', async () => {
			const params = {
				...teacherParams,
				route: { scopeId: course._id },
			};
			const response = await courseMembersService.find(params);
			expect(response).to.not.equal(undefined);
		});

		it('does not allow access for students and other users', async () => {
			const params = {
				...studentParams,
				route: { scopeId: course._id },
			};
			try {
				await courseMembersService.find(params);
				throw new Error('The previous call should have failed.');
			} catch (err) {
				expect(err).to.be.instanceOf(Forbidden);
			}
		});
	});

	describe('in a large course', () => {
		let teachers;
		let substitutionTeachers;
		let students;
		let course;

		let teacherParams;
		let substitutionTeacherParams;
		let studentParams;

		const toId = (item) => item._id;
		const toIdString = (item) => item._id.toString();

		before(async function before() {
			this.timeout(8000);
			teachers = [
				await testObjects.createTestUser(),
				await testObjects.createTestUser(),
			];
			substitutionTeachers = [await testObjects.createTestUser()];
			students = [
				await testObjects.createTestUser(), await testObjects.createTestUser(),
				await testObjects.createTestUser(), await testObjects.createTestUser(),
				await testObjects.createTestUser(), await testObjects.createTestUser(),
				await testObjects.createTestUser(), await testObjects.createTestUser(),
			];
			course = await testObjects.createTestCourse({
				teacherIds: teachers.map(toId),
				substitutionIds: substitutionTeachers.map(toId),
				userIds: students.map(toId),
			});
			teacherParams = await generateRequestParamsFromUser(teachers[0]);
			substitutionTeacherParams = await generateRequestParamsFromUser(substitutionTeachers[0]);
			studentParams = await generateRequestParamsFromUser(students[0]);
		});

		after(testObjects.cleanup);

		it('returns all members', async () => {
			const response = await courseMembersService.find({ route: { scopeId: course._id } });
			expect(Object.keys(response).length)
				.to.equal(teachers.length + substitutionTeachers.length + students.length);
			expect(Object.keys(response)).to.include.members(teachers.map(toIdString));
			expect(Object.keys(response)).to.include.members(substitutionTeachers.map(toIdString));
			expect(Object.keys(response)).to.include.members(students.map(toIdString));
		});

		it('allows access to teachers and substitution teachers', async () => {
			let params = {
				...teacherParams,
				route: { scopeId: course._id },
			};
			let response = await courseMembersService.find(params);
			expect(response).to.not.equal(undefined);

			params = {
				...substitutionTeacherParams,
				route: { scopeId: course._id },
			};
			response = await courseMembersService.find(params);
			expect(response).to.not.equal(undefined);
		});

		it('does not allow access for students and other users', async () => {
			const params = {
				...studentParams,
				route: { scopeId: course._id },
			};
			try {
				await courseMembersService.find(params);
				throw new Error('The previous call should have failed.');
			} catch (err) {
				expect(err).to.be.instanceOf(Forbidden);
			}
		});
	});
});
<|endoftext|>


<commit_before>/* eslint-disable no-tabs */
'use strict';

const LUtils = require('larvitutils');
const async = require('async');

function Orders(options) {
	this.options = options || {};

	if (!options.db) throw new Error('Missing required option "db"');

	if (!options.log) {
		const tmpLUtils = new LUtils();

		options.log = new tmpLUtils.lUtils.Log();
	}

	if (!options.lUtils) options.lUtils = new LUtils();

	this.options = options;

	for (const key of Object.keys(options)) {
		this[key] = options[key];
	}
}

Orders.prototype.get = function (cb) {
	const tasks = [];
	let orders = {};

	let hits;

	// Get basic orders
	tasks.push(cb => {
		const dbFields = [];

		let sql = ' FROM orders WHERE 1';
		let hitsSql = '';

		if (this.uuids !== undefined) {
			if (!(this.uuids instanceof Array)) {
				this.uuids = [this.uuids];
			}

			if (this.uuids.length === 0) {
				sql += '	AND 0';
			} else {
				sql += '	AND uuid IN (';

				for (let i = 0; this.uuids[i] !== undefined; i++) {
					const buffer = this.lUtils.uuidToBuffer(this.uuids[i]);

					if (buffer === false) {
						return cb(new Error('Invalid order uuid supplied'));
					}

					sql += '?,';
					dbFields.push(buffer);
				}

				sql = sql.substring(0, sql.length - 1) + ')';
			}
		}

		if (this.q !== undefined) {
			sql += ' AND (\n';
			sql += '		(\n';
			sql += '   			uuid IN (SELECT DISTINCT orderUuid FROM orders_orders_fields WHERE fieldValue LIKE ?)\n';
			sql += '		)\n';
			dbFields.push('%' + this.q + '%');

			sql += ' 	OR uuid IN (\n';
			sql += '		SELECT DISTINCT orderUuid\n';
			sql += '		FROM orders_rows WHERE rowUuid IN (\n';
			sql += '			SELECT rowUuid FROM orders_rows_fields WHERE rowStrValue LIKE ?\n';
			sql += '		)\n';
			sql += '	)\n';
			sql += ' )\n';
			dbFields.push('%' + this.q + '%');
		}

		if (this.matchAllFields !== undefined) {
			for (let fieldName in this.matchAllFields) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.matchAllFields[fieldName]);
			}
		}

		if (this.fieldNotEqualTo !== undefined) {
			for (let fieldName in this.fieldNotEqualTo) {
				sql += '	AND orders.uuid NOT IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.fieldNotEqualTo[fieldName]);
			}
		}

		if (this.fieldGreaterThan !== undefined) {
			for (let fieldName in this.fieldGreaterThan) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue >= ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.fieldGreaterThan[fieldName]);
			}
		}

		if (this.matchAllRowFields !== undefined) {
			for (let rowFieldName in this.matchAllRowFields) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_rows\n';
				sql += '		WHERE rowUuid IN (\n';
				sql += '			SELECT rowUuid FROM orders_rows_fields WHERE rowFieldUuid = (SELECT uuid FROM orders_rowFields WHERE name = ?) AND ';

				if (parseInt(this.matchAllRowFields[rowFieldName]) === this.matchAllRowFields[rowFieldName]) {
					sql += 'rowIntValue = ?\n';
				} else {
					sql += 'rowStrValue = ?\n';
				}

				sql += '		)';
				sql += '	)';

				dbFields.push(rowFieldName);
				dbFields.push(this.matchAllRowFields[rowFieldName]);
			}
		}

		sql += '	ORDER BY created DESC';

		hitsSql = 'SELECT COUNT(*) AS hits' + sql;
		sql = 'SELECT *' + sql;

		if (this.limit) {
			sql += ' LIMIT ' + parseInt(this.limit);
			if (this.offset) {
				sql += ' OFFSET ' + parseInt(this.offset);
			}
		}

		const tasks = [];

		tasks.push(cb => {
			this.db.query(sql, dbFields, (err, rows) => {
				if (err) return cb(err);

				for (let i = 0; rows[i] !== undefined; i++) {
					rows[i].uuid = this.lUtils.formatUuid(rows[i].uuid);
					orders[rows[i].uuid] = {};
					orders[rows[i].uuid].uuid = rows[i].uuid;
					orders[rows[i].uuid].created = rows[i].created;
				}

				cb();
			});
		});

		tasks.push(cb => {
			this.db.query(hitsSql, dbFields, (err, rows) => {
				if (err) return cb(err);

				hits = rows[0].hits;

				cb();
			});
		});

		async.parallel(tasks, cb);
	});

	// Get fields
	tasks.push(cb => {
		const dbFields = [];

		let sql;

		if (!this.returnFields || Object.keys(orders).length === 0) return cb();

		sql = 'SELECT orderUuid, name AS fieldName, fieldValue\n';
		sql += 'FROM orders_orders_fields JOIN orders_orderFields ON fieldUuid = uuid\n';
		sql += 'WHERE\n';
		sql += '	orderUuid IN (';

		for (let orderUuid in orders) {
			const buffer = this.lUtils.uuidToBuffer(orderUuid);

			if (buffer === false) {
				return cb(new Error('Invalid order uuid supplied'));
			}

			sql += '?,';
			dbFields.push(buffer);
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';

		sql += '	AND name IN (';

		for (let i = 0; this.returnFields[i] !== undefined; i++) {
			sql += '?,';
			dbFields.push(this.returnFields[i]);
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';

		this.db.query(sql, dbFields, (err, rows) => {
			if (err) return cb(err);

			for (let i = 0; rows[i] !== undefined; i++) {
				const row = rows[i];

				row.orderUuid = this.lUtils.formatUuid(row.orderUuid);

				if (orders[row.orderUuid].fields === undefined) {
					orders[row.orderUuid].fields = {};
				}

				if (orders[row.orderUuid].fields[row.fieldName] === undefined) {
					orders[row.orderUuid].fields[row.fieldName] = [];
				}

				orders[row.orderUuid].fields[row.fieldName].push(row.fieldValue);
			}

			cb();
		});
	});

	// Get rows
	tasks.push(cb => {
		const dbFields = [];

		let sql;

		if (this.returnRowFields === undefined || Object.keys(orders).length === 0) return cb();

		sql = 'SELECT r.orderUuid, r.rowUuid, f.name AS fieldName, rf.rowIntValue, rf.rowStrValue\n';
		sql += 'FROM orders_rows r\n';
		sql += '	LEFT JOIN orders_rows_fields	rf	ON rf.rowUuid = r.rowUuid\n';
		sql += '	LEFT JOIN orders_rowFields	f	ON f.uuid = rf.rowFieldUuid\n';
		sql += 'WHERE r.orderUuid IN (';

		for (let orderUuid in orders) {
			const buffer = this.lUtils.uuidToBuffer(orderUuid);

			if (buffer === false) {
				return cb(new Error('Invalid order uuid supplied'));
			}

			sql += '?,';
			dbFields.push(buffer);
		}

		sql = sql.substring(0, sql.length - 1) + ')';
		sql += '	AND f.name IN (';

		for (let i = 0; this.returnRowFields[i] !== undefined; i++) {
			sql += '?,';
			dbFields.push(this.returnRowFields[i]);
		}

		sql = sql.substring(0, sql.length - 1) + ')';

		this.db.query(sql, dbFields, (err, rows) => {
			if (err) return cb(err);

			for (let i = 0; rows[i] !== undefined; i++) {
				const row = rows[i];

				row.orderUuid = this.lUtils.formatUuid(row.orderUuid);
				row.rowUuid = this.lUtils.formatUuid(row.rowUuid);

				if (orders[row.orderUuid].rows === undefined) {
					orders[row.orderUuid].rows = {};
				}

				if (orders[row.orderUuid].rows[row.rowUuid] === undefined) {
					orders[row.orderUuid].rows[row.rowUuid] = {uuid: row.rowUuid};
				}

				if (orders[row.orderUuid].rows[row.rowUuid][row.fieldName] === undefined) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName] = [];
				}

				if (row.rowIntValue !== null) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName].push(row.rowIntValue);
				} else if (row.rowStrValue !== null) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName].push(row.rowStrValue);
				}
			}

			cb();
		});
	});

	async.series(tasks, function (err) {
		if (err) return cb(err);

		cb(null, orders, hits);
	});
};

exports = module.exports = Orders;
<commit_msg>propty name fieldGreaterThan changed to fieldGreaterThanOrEqualTo<commit_after>/* eslint-disable no-tabs */
'use strict';

const LUtils = require('larvitutils');
const async = require('async');

function Orders(options) {
	this.options = options || {};

	if (!options.db) throw new Error('Missing required option "db"');

	if (!options.log) {
		const tmpLUtils = new LUtils();

		options.log = new tmpLUtils.lUtils.Log();
	}

	if (!options.lUtils) options.lUtils = new LUtils();

	this.options = options;

	for (const key of Object.keys(options)) {
		this[key] = options[key];
	}
}

Orders.prototype.get = function (cb) {
	const tasks = [];
	let orders = {};

	let hits;

	// Get basic orders
	tasks.push(cb => {
		const dbFields = [];

		let sql = ' FROM orders WHERE 1';
		let hitsSql = '';

		if (this.uuids !== undefined) {
			if (!(this.uuids instanceof Array)) {
				this.uuids = [this.uuids];
			}

			if (this.uuids.length === 0) {
				sql += '	AND 0';
			} else {
				sql += '	AND uuid IN (';

				for (let i = 0; this.uuids[i] !== undefined; i++) {
					const buffer = this.lUtils.uuidToBuffer(this.uuids[i]);

					if (buffer === false) {
						return cb(new Error('Invalid order uuid supplied'));
					}

					sql += '?,';
					dbFields.push(buffer);
				}

				sql = sql.substring(0, sql.length - 1) + ')';
			}
		}

		if (this.q !== undefined) {
			sql += ' AND (\n';
			sql += '		(\n';
			sql += '   			uuid IN (SELECT DISTINCT orderUuid FROM orders_orders_fields WHERE fieldValue LIKE ?)\n';
			sql += '		)\n';
			dbFields.push('%' + this.q + '%');

			sql += ' 	OR uuid IN (\n';
			sql += '		SELECT DISTINCT orderUuid\n';
			sql += '		FROM orders_rows WHERE rowUuid IN (\n';
			sql += '			SELECT rowUuid FROM orders_rows_fields WHERE rowStrValue LIKE ?\n';
			sql += '		)\n';
			sql += '	)\n';
			sql += ' )\n';
			dbFields.push('%' + this.q + '%');
		}

		if (this.matchAllFields !== undefined) {
			for (let fieldName in this.matchAllFields) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.matchAllFields[fieldName]);
			}
		}

		if (this.fieldNotEqualTo !== undefined) {
			for (let fieldName in this.fieldNotEqualTo) {
				sql += '	AND orders.uuid NOT IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.fieldNotEqualTo[fieldName]);
			}
		}

		if (this.fieldGreaterThanOrEqualTo !== undefined) {
			for (let fieldName in this.fieldGreaterThanOrEqualTo) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_orders_fields\n';
				sql += '		WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue >= ?\n';
				sql += ')';

				dbFields.push(fieldName);
				dbFields.push(this.fieldGreaterThanOrEqualTo[fieldName]);
			}
		}

		if (this.matchAllRowFields !== undefined) {
			for (let rowFieldName in this.matchAllRowFields) {
				sql += '	AND orders.uuid IN (\n';
				sql += '		SELECT DISTINCT orderUuid\n';
				sql += '		FROM orders_rows\n';
				sql += '		WHERE rowUuid IN (\n';
				sql += '			SELECT rowUuid FROM orders_rows_fields WHERE rowFieldUuid = (SELECT uuid FROM orders_rowFields WHERE name = ?) AND ';

				if (parseInt(this.matchAllRowFields[rowFieldName]) === this.matchAllRowFields[rowFieldName]) {
					sql += 'rowIntValue = ?\n';
				} else {
					sql += 'rowStrValue = ?\n';
				}

				sql += '		)';
				sql += '	)';

				dbFields.push(rowFieldName);
				dbFields.push(this.matchAllRowFields[rowFieldName]);
			}
		}

		sql += '	ORDER BY created DESC';

		hitsSql = 'SELECT COUNT(*) AS hits' + sql;
		sql = 'SELECT *' + sql;

		if (this.limit) {
			sql += ' LIMIT ' + parseInt(this.limit);
			if (this.offset) {
				sql += ' OFFSET ' + parseInt(this.offset);
			}
		}

		const tasks = [];

		tasks.push(cb => {
			this.db.query(sql, dbFields, (err, rows) => {
				if (err) return cb(err);

				for (let i = 0; rows[i] !== undefined; i++) {
					rows[i].uuid = this.lUtils.formatUuid(rows[i].uuid);
					orders[rows[i].uuid] = {};
					orders[rows[i].uuid].uuid = rows[i].uuid;
					orders[rows[i].uuid].created = rows[i].created;
				}

				cb();
			});
		});

		tasks.push(cb => {
			this.db.query(hitsSql, dbFields, (err, rows) => {
				if (err) return cb(err);

				hits = rows[0].hits;

				cb();
			});
		});

		async.parallel(tasks, cb);
	});

	// Get fields
	tasks.push(cb => {
		const dbFields = [];

		let sql;

		if (!this.returnFields || Object.keys(orders).length === 0) return cb();

		sql = 'SELECT orderUuid, name AS fieldName, fieldValue\n';
		sql += 'FROM orders_orders_fields JOIN orders_orderFields ON fieldUuid = uuid\n';
		sql += 'WHERE\n';
		sql += '	orderUuid IN (';

		for (let orderUuid in orders) {
			const buffer = this.lUtils.uuidToBuffer(orderUuid);

			if (buffer === false) {
				return cb(new Error('Invalid order uuid supplied'));
			}

			sql += '?,';
			dbFields.push(buffer);
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';

		sql += '	AND name IN (';

		for (let i = 0; this.returnFields[i] !== undefined; i++) {
			sql += '?,';
			dbFields.push(this.returnFields[i]);
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';

		this.db.query(sql, dbFields, (err, rows) => {
			if (err) return cb(err);

			for (let i = 0; rows[i] !== undefined; i++) {
				const row = rows[i];

				row.orderUuid = this.lUtils.formatUuid(row.orderUuid);

				if (orders[row.orderUuid].fields === undefined) {
					orders[row.orderUuid].fields = {};
				}

				if (orders[row.orderUuid].fields[row.fieldName] === undefined) {
					orders[row.orderUuid].fields[row.fieldName] = [];
				}

				orders[row.orderUuid].fields[row.fieldName].push(row.fieldValue);
			}

			cb();
		});
	});

	// Get rows
	tasks.push(cb => {
		const dbFields = [];

		let sql;

		if (this.returnRowFields === undefined || Object.keys(orders).length === 0) return cb();

		sql = 'SELECT r.orderUuid, r.rowUuid, f.name AS fieldName, rf.rowIntValue, rf.rowStrValue\n';
		sql += 'FROM orders_rows r\n';
		sql += '	LEFT JOIN orders_rows_fields	rf	ON rf.rowUuid = r.rowUuid\n';
		sql += '	LEFT JOIN orders_rowFields	f	ON f.uuid = rf.rowFieldUuid\n';
		sql += 'WHERE r.orderUuid IN (';

		for (let orderUuid in orders) {
			const buffer = this.lUtils.uuidToBuffer(orderUuid);

			if (buffer === false) {
				return cb(new Error('Invalid order uuid supplied'));
			}

			sql += '?,';
			dbFields.push(buffer);
		}

		sql = sql.substring(0, sql.length - 1) + ')';
		sql += '	AND f.name IN (';

		for (let i = 0; this.returnRowFields[i] !== undefined; i++) {
			sql += '?,';
			dbFields.push(this.returnRowFields[i]);
		}

		sql = sql.substring(0, sql.length - 1) + ')';

		this.db.query(sql, dbFields, (err, rows) => {
			if (err) return cb(err);

			for (let i = 0; rows[i] !== undefined; i++) {
				const row = rows[i];

				row.orderUuid = this.lUtils.formatUuid(row.orderUuid);
				row.rowUuid = this.lUtils.formatUuid(row.rowUuid);

				if (orders[row.orderUuid].rows === undefined) {
					orders[row.orderUuid].rows = {};
				}

				if (orders[row.orderUuid].rows[row.rowUuid] === undefined) {
					orders[row.orderUuid].rows[row.rowUuid] = {uuid: row.rowUuid};
				}

				if (orders[row.orderUuid].rows[row.rowUuid][row.fieldName] === undefined) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName] = [];
				}

				if (row.rowIntValue !== null) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName].push(row.rowIntValue);
				} else if (row.rowStrValue !== null) {
					orders[row.orderUuid].rows[row.rowUuid][row.fieldName].push(row.rowStrValue);
				}
			}

			cb();
		});
	});

	async.series(tasks, function (err) {
		if (err) return cb(err);

		cb(null, orders, hits);
	});
};

exports = module.exports = Orders;
<|endoftext|>


<commit_before>var Model = require('../../../src/core/model');
var RangeFilter = require('../../../src/windshaft/filters/range');
var HistogramDataviewModel = require('../../../src/dataviews/histogram-dataview-model');

describe('dataviews/histogram-dataview-model', function () {
  beforeEach(function () {
    this.map = jasmine.createSpyObj('map', ['getViewBounds', 'bind', 'reload']);
    this.map.getViewBounds.and.returnValue([[1, 2], [3, 4]]);
    var windshaftMap = jasmine.createSpyObj('windhsaftMap', ['bind']);
    this.filter = new RangeFilter();
    this.layer = new Model();
    this.layer.getDataProvider = function () {};
    this.model = new HistogramDataviewModel({}, {
      map: this.map,
      windshaftMap: windshaftMap,
      layer: this.layer,
      filter: this.filter
    });
  });

  describe('when column changes', function () {
    it('should reload map and force fetch', function () {
      this.map.reload.calls.reset();
      this.model.set('column', 'random_col');
      expect(this.map.reload).toHaveBeenCalledWith({ forceFetch: true, sourceLayerId: undefined });
    });
  });

  describe('when bins change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('bins', 123);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  describe('when start change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('start', 0);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  describe('when end change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('end', 0);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  it('should include the bbox after the first fetch', function () {
    this.model.set('url', 'http://example.com', { silent: true });
    this.model.set('boundingBox', 'fakeBoundingBox');
    spyOn(this.model, 'sync').and.callFake(function (args) {
      this.model.set('data', 'something');
    }.bind(this));

    // url doesn't include bbox the first time
    expect(this.model.url()).toEqual('http://example.com?bins=10');

    this.model.fetch();

    // url now has the bbox
    expect(this.model.url()).toEqual('http://example.com?bins=10&bbox=fakeBoundingBox');
  });

  it('should calculate start, end and bins after the first fetch', function () {
    var histogramData = {
      'bin_width': 10,
      'bins_count': 3,
      'bins_start': 1,
      'nulls': 0
    };

    spyOn(this.model, 'sync').and.callFake(function (method, model, options) {
      options.success(histogramData);
    });

    expect(this.model.get('start')).toBeUndefined();
    expect(this.model.get('end')).toBeUndefined();

    this.model.fetch();

    expect(this.model.get('start')).toEqual(1);
    expect(this.model.get('end')).toEqual(31);
    expect(this.model.get('bins')).toEqual(3);
  });

  it('should parse the bins', function () {
    var data = {
      bin_width: 14490.25,
      bins: [
        { bin: 0, freq: 2, max: 70151, min: 55611 },
        { bin: 1, freq: 2, max: 79017, min: 78448 },
        { bin: 3, freq: 1, max: 113572, min: 113572 }
      ],
      bins_count: 4,
      bins_start: 55611,
      nulls: 0,
      type: 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(4);
    expect(JSON.stringify(parsedData)).toBe('[{"bin":0,"start":55611,"end":70101.25,"freq":2,"max":70151,"min":55611},{"bin":1,"start":70101.25,"end":84591.5,"freq":2,"max":79017,"min":78448},{"bin":2,"start":84591.5,"end":99081.75,"freq":0},{"bin":3,"start":99081.75,"end":113572,"freq":1,"max":113572,"min":113572}]');
  });

  it('parser do not fails when there are no bins', function () {
    var data = {
      bin_width: 0,
      bins: [],
      bins_count: 0,
      bins_start: 0,
      nulls: 0,
      type: 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(0);
  });

  it('should parse the bins and fix end bucket issues', function () {
    var data = {
      'bin_width': 1041.66645833333,
      'bins_count': 48,
      'bins_start': 0.01,
      'nulls': 0,
      'avg': 55.5007561961441,
      'bins': [{
        'bin': 47,
        'min': 50000,
        'max': 50000,
        'avg': 50000,
        'freq': 6
        // NOTE - The end of this bucket is 48 * 1041.66645833333 = 49999.98999999984
        // but it must be corrected to 50.000.
      }],
      'type': 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(48);
    expect(parsedData[47].end).not.toBeLessThan(parsedData[47].max);
  });

  describe('when layer changes meta', function () {
    beforeEach(function () {
      expect(this.model.filter.get('column_type')).not.toEqual('date');
      this.model.layer.set({
        meta: {
          column_type: 'date'
        }
      });
    });

    it('should change the filter column_type', function () {
      expect(this.model.filter.get('column_type')).toEqual('date');
    });
  });

  describe('.url', function () {
    it('should generate a URL by default', function () {
      this.model.set('url', 'http://example.com');
      expect(this.model.url()).toEqual('http://example.com?bins=10');
    });

    it('should include start, end and bins when own_filter is enabled', function () {
      this.model.set({
        'url': 'http://example.com',
        'start': 0,
        'end': 10,
        'bins': 25
      });
      expect(this.model.url()).toEqual('http://example.com?start=0&end=10&bins=25');

      this.model.enableFilter();

      expect(this.model.url()).toEqual('http://example.com?own_filter=1');
    });
  });

  describe('.enableFilter', function () {
    it('should set the own_filter attribute', function () {
      expect(this.model.get('own_filter')).toBeUndefined();

      this.model.enableFilter();

      expect(this.model.get('own_filter')).toEqual(1);
    });
  });

  describe('.disabeFilter', function () {
    it('should unset the own_filter attribute', function () {
      this.model.enableFilter();
      this.model.disableFilter();

      expect(this.model.get('own_filter')).toBeUndefined();
    });
  });
});
<commit_msg>Removed unnecessary blank line<commit_after>var Model = require('../../../src/core/model');
var RangeFilter = require('../../../src/windshaft/filters/range');
var HistogramDataviewModel = require('../../../src/dataviews/histogram-dataview-model');

describe('dataviews/histogram-dataview-model', function () {
  beforeEach(function () {
    this.map = jasmine.createSpyObj('map', ['getViewBounds', 'bind', 'reload']);
    this.map.getViewBounds.and.returnValue([[1, 2], [3, 4]]);
    var windshaftMap = jasmine.createSpyObj('windhsaftMap', ['bind']);
    this.filter = new RangeFilter();
    this.layer = new Model();
    this.layer.getDataProvider = function () {};
    this.model = new HistogramDataviewModel({}, {
      map: this.map,
      windshaftMap: windshaftMap,
      layer: this.layer,
      filter: this.filter
    });
  });

  describe('when column changes', function () {
    it('should reload map and force fetch', function () {
      this.map.reload.calls.reset();
      this.model.set('column', 'random_col');
      expect(this.map.reload).toHaveBeenCalledWith({ forceFetch: true, sourceLayerId: undefined });
    });
  });

  describe('when bins change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('bins', 123);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  describe('when start change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('start', 0);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  describe('when end change', function () {
    beforeEach(function () {
      this.map.reload.calls.reset();
      spyOn(this.model, 'fetch');
      spyOn(this.model.filter, 'unsetRange');

      this.model.set('end', 0);
    });

    it('should refresh data on bins change', function () {
      expect(this.map.reload).not.toHaveBeenCalled();
      expect(this.model.fetch).toHaveBeenCalled();
    });

    it('should disable filter', function () {
      expect(this.model.get('own_filter')).toBeUndefined();
    });

    it('should unset range filter', function () {
      expect(this.model.filter.unsetRange).toHaveBeenCalled();
    });
  });

  it('should include the bbox after the first fetch', function () {
    this.model.set('url', 'http://example.com', { silent: true });
    this.model.set('boundingBox', 'fakeBoundingBox');
    spyOn(this.model, 'sync').and.callFake(function (args) {
      this.model.set('data', 'something');
    }.bind(this));

    // url doesn't include bbox the first time
    expect(this.model.url()).toEqual('http://example.com?bins=10');

    this.model.fetch();

    // url now has the bbox
    expect(this.model.url()).toEqual('http://example.com?bins=10&bbox=fakeBoundingBox');
  });

  it('should calculate start, end and bins after the first fetch', function () {
    var histogramData = {
      'bin_width': 10,
      'bins_count': 3,
      'bins_start': 1,
      'nulls': 0
    };

    spyOn(this.model, 'sync').and.callFake(function (method, model, options) {
      options.success(histogramData);
    });

    expect(this.model.get('start')).toBeUndefined();
    expect(this.model.get('end')).toBeUndefined();

    this.model.fetch();

    expect(this.model.get('start')).toEqual(1);
    expect(this.model.get('end')).toEqual(31);
    expect(this.model.get('bins')).toEqual(3);
  });

  it('should parse the bins', function () {
    var data = {
      bin_width: 14490.25,
      bins: [
        { bin: 0, freq: 2, max: 70151, min: 55611 },
        { bin: 1, freq: 2, max: 79017, min: 78448 },
        { bin: 3, freq: 1, max: 113572, min: 113572 }
      ],
      bins_count: 4,
      bins_start: 55611,
      nulls: 0,
      type: 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(4);
    expect(JSON.stringify(parsedData)).toBe('[{"bin":0,"start":55611,"end":70101.25,"freq":2,"max":70151,"min":55611},{"bin":1,"start":70101.25,"end":84591.5,"freq":2,"max":79017,"min":78448},{"bin":2,"start":84591.5,"end":99081.75,"freq":0},{"bin":3,"start":99081.75,"end":113572,"freq":1,"max":113572,"min":113572}]');
  });

  it('parser do not fails when there are no bins', function () {
    var data = {
      bin_width: 0,
      bins: [],
      bins_count: 0,
      bins_start: 0,
      nulls: 0,
      type: 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(0);
  });

  it('should parse the bins and fix end bucket issues', function () {
    var data = {
      'bin_width': 1041.66645833333,
      'bins_count': 48,
      'bins_start': 0.01,
      'nulls': 0,
      'avg': 55.5007561961441,
      'bins': [{
        'bin': 47,
        'min': 50000,
        'max': 50000,
        'avg': 50000,
        'freq': 6
        // NOTE - The end of this bucket is 48 * 1041.66645833333 = 49999.98999999984
        // but it must be corrected to 50.000.
      }],
      'type': 'histogram'
    };

    this.model.parse(data);

    var parsedData = this.model.getData();

    expect(data.nulls).toBe(0);
    expect(parsedData.length).toBe(48);
    expect(parsedData[47].end).not.toBeLessThan(parsedData[47].max);
  });

  describe('when layer changes meta', function () {
    beforeEach(function () {
      expect(this.model.filter.get('column_type')).not.toEqual('date');
      this.model.layer.set({
        meta: {
          column_type: 'date'
        }
      });
    });

    it('should change the filter column_type', function () {
      expect(this.model.filter.get('column_type')).toEqual('date');
    });
  });

  describe('.url', function () {
    it('should generate a URL by default', function () {
      this.model.set('url', 'http://example.com');
      expect(this.model.url()).toEqual('http://example.com?bins=10');
    });

    it('should include start, end and bins when own_filter is enabled', function () {
      this.model.set({
        'url': 'http://example.com',
        'start': 0,
        'end': 10,
        'bins': 25
      });
      expect(this.model.url()).toEqual('http://example.com?start=0&end=10&bins=25');

      this.model.enableFilter();

      expect(this.model.url()).toEqual('http://example.com?own_filter=1');
    });
  });

  describe('.enableFilter', function () {
    it('should set the own_filter attribute', function () {
      expect(this.model.get('own_filter')).toBeUndefined();

      this.model.enableFilter();

      expect(this.model.get('own_filter')).toEqual(1);
    });
  });

  describe('.disabeFilter', function () {
    it('should unset the own_filter attribute', function () {
      this.model.enableFilter();
      this.model.disableFilter();

      expect(this.model.get('own_filter')).toBeUndefined();
    });
  });
});
<|endoftext|>


<commit_before>goog.module('measurementLibrary.storage.CookiesStorage.testing.findAutoDomain_');
goog.setTestOnly();

const CookiesStorage = goog.require('measurementLibrary.storage.CookiesStorage');

// These tests replicate the meaningful examples from this
// table: https://url.spec.whatwg.org/#host-registrable-domain
// Some examples in the table are not able to be tested because
// these tests do not use a real javascript document object.
describe('The findAutoDomain method', () => {
  let testDocument;
  let setupDocument;
  const storage = new CookiesStorage({});

  beforeEach(() => {
    // sets up testDocument, an object that acts like the window.document object
    // when dealing with cookies with a specified domain. Allows for testing on
    // multiple domains.
    setupDocument = (domain, registrableDomain) => {
      testDocument = {'cook': ''};
      testDocument['domain'] = domain;
      Object.defineProperty(testDocument, 'cookie', {
        get() {
          return testDocument.cook;
        },
        set(newValue) {
          if (newValue.includes(`domain=${registrableDomain}`)) {
            testDocument.cook = newValue;
          }
        },
        configurable: true,
      });
    };
  });

  it('returns null when domain is a public suffix', () => {
    setupDocument('com');

    expect(storage.findAutoDomain_(testDocument)).toBe(null);
  });

  it('returns null when domain does not contain a public suffix', () => {
    setupDocument('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]');

    expect(storage.findAutoDomain_(testDocument)).toBe(null);
  });

  it('returns registrableDomain when domain is a valid subdomain', () => {
    setupDocument('example.com', 'example.com');

    expect(storage.findAutoDomain_(testDocument)).toBe('example.com');

    setupDocument('www.example.com', 'example.com');

    expect(storage.findAutoDomain_(testDocument)).toBe('example.com');

    setupDocument('sub.www.example.com', 'example.com');

    expect(storage.findAutoDomain_(testDocument)).toBe('example.com');
  });
});
<commit_msg>Add additional tests.<commit_after>goog.module('measurementLibrary.storage.CookiesStorage.testing.cookieSave');
goog.setTestOnly();

const CookiesStorage = goog.require('measurementLibrary.storage.CookiesStorage');

const oneSecondInMilliseconds = 1000;

describe('The save method for cookiesStorage', () => {
  const storage = new CookiesStorage({});

  const removeCookie = (key) => {
    const pastDate = 'Thu, 01 Jan 1970 00:00:00 GMT';
    document.cookie =
      `ml_${key}=;expires=${pastDate}`;
  };

  const setExpectedExpiry = (min, max, expiryInSeconds) => {
    max.setMilliseconds(max.getMilliseconds() +
      (expiryInSeconds + 1) * oneSecondInMilliseconds);
    min.setMilliseconds(min.getMilliseconds() +
      expiryInSeconds * oneSecondInMilliseconds);
  };

  it('Saves cookies with null and undefined values', () => {
    storage.save('null', null);

    expect(document.cookie.includes('ml_null=null')).toBe(true);
  });

  it('Saves cookies with falsey and truthy string values', () => {
    storage.save('Hello', 'World');

    expect(document.cookie.includes('ml_Hello="World"')).toBe(true);

    removeCookie('Hello');

    storage.save('Hello', '');

    expect(document.cookie.includes('ml_Hello=""')).toBe(true);

    removeCookie('Hello');
  });

  it('Saves cookies with array values', () => {
    storage.save('array', [1, 'hello', 3, 'world']);

    const arrayString = '[1,"hello",3,"world"]';

    expect(document.cookie.includes(`ml_array=${arrayString}`)).toBe(true);

    removeCookie('array');
  });

  it('Saves cookies with object values', () => {
    storage.save('obj', {'hello': 'world'});

    const objString = '{"hello":"world"}';

    expect(document.cookie.includes(`ml_obj=${objString}`)).toBe(true);

    removeCookie('obj');
  });

  it('Saves cookies with number values', () => {
    storage.save('num', 10);

    const numString = '10';

    expect(document.cookie.includes(`ml_num=${numString}`)).toBe(true);

    removeCookie('num');
  });

  it('Saves cookies with boolean values', () => {
    storage.save('bool', true);

    const boolString = 'true';

    expect(document.cookie.includes(`ml_bool=${boolString}`)).toBe(true);

    removeCookie('bool');
  });

  it('Saves multiple cookies', () => {
    storage.save('bool', true);
    const boolString = 'true';

    storage.save('num', 10);
    const numString = '10';

    storage.save('hello', 'world');

    expect(document.cookie.includes(`ml_bool=${boolString}`)).toBe(true);

    expect(document.cookie.includes(`ml_num=${numString}`)).toBe(true);

    expect(document.cookie.includes(`ml_hello="world"`)).toBe(true);

    removeCookie('bool');
    removeCookie('num');
    removeCookie('hello');
  });

  it('Overwrites cookies saved with the same key', () => {
    storage.save('hello', 'world');

    expect(document.cookie.includes(`ml_hello="world"`)).toBe(true);

    storage.save('hello', 'goodbye');

    expect(document.cookie.includes(`ml_hello="world"`)).toBe(false);

    expect(document.cookie.includes(`ml_hello="goodbye"`)).toBe(true);

    removeCookie('hello');
  });

  it('Saves cookies without a prefix', () => {
    const noPrefixStorage = new CookiesStorage({'prefix': '', 'expires': '1'});

    noPrefixStorage.save('hello', 'world');

    expect(document.cookie.includes(`hello="world"`)).toBe(true);

    removeCookie('hello');
  });

  it('Saves cookies with a custom prefix', () => {
    const noPrefixStorage =
      new CookiesStorage({'prefix': 'p_', 'expires': '1'});

    noPrefixStorage.save('hello', 'world');

    expect(document.cookie.includes(`p_hello="world"`)).toBe(true);
  });

  it('Saves cookies with correct domain', () => {
    const expiryInSeconds = 3;

    const fullAttributeStorage = new CookiesStorage(
      {'prefix': 'pre', 'expires': expiryInSeconds, 'domain': document.domain});

    let testCookie = '';
    spyOn(fullAttributeStorage, 'setCookie').and.callFake((cookie) => {
      testCookie = cookie;
    });

    fullAttributeStorage.save('hello', 'goodbye');

    expect(testCookie.includes(`prehello="goodbye"`)).toBe(true);

    expect(testCookie.includes(`domain=${document.domain}`)).toBe(true);
  });

  it('Saves cookies with correct expiry', () => {
    const expiryInSeconds = 3;

    const fullAttributeStorage = new CookiesStorage(
      {'prefix': 'pre', 'expires': expiryInSeconds, 'domain': document.domain});

    let testCookie = '';
    spyOn(fullAttributeStorage, 'setCookie').and.callFake((cookie) => {
      testCookie = cookie;
    });

    const expiresStringLength = 8;
    const UTCStringLength = 29;

    const maxExpectedExpiryDate = new Date();
    const minExpectedExpiryDate = new Date();
    setExpectedExpiry(minExpectedExpiryDate, maxExpectedExpiryDate,
      expiryInSeconds);

    fullAttributeStorage.save('hello', 'goodbye');

    expect(testCookie.includes(`prehello="goodbye"`)).toBe(true);

    const beginIndex = testCookie.indexOf('expires=');

    const expiryDateString = testCookie.substring(beginIndex +
      expiresStringLength, beginIndex + UTCStringLength + expiresStringLength);

    const expiryDate = new Date(expiryDateString);

    expect(expiryDate).toBeGreaterThanOrEqual(minExpectedExpiryDate);
    expect(expiryDate).toBeLessThanOrEqual(maxExpectedExpiryDate);
  });
});
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.
if ( process.argv[ <commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.
if ( process.argv[ 2<|endoftext|>


<commit_before>const { join } = require('path')

Msa.registerParam({
	"db.type": {
		desc: "Database type",
		choices: [ "sqlite", "mysql", "postgre" ]
	},
	"db.path": {
		desc: "Path to DB file (sqlite only)",
	},
	"db.pool.min": {
		defVal: 0
	},
	"db.pool.max": {
		defVal: 5
	},
	"db.pool.acquire": {
		defVal: 10000
	},
	"db.pool.idle": {
		defVal: 30000
	},
})
<commit_msg>Migrate to ParamDef<commit_after>const { join } = require('path')

new Msa.ParamDef("db.type", {
	desc: "Database type",
	choices: [ "sqlite", "mysql", "postgre" ]
})
new Msa.ParamDef("db.path", {
	desc: "Path to DB file (sqlite only)"
})
new Msa.ParamDef("db.pool.min", {
	defVal: 0
})
new Msa.ParamDef("db.pool.max", {
	defVal: 5
})
new Msa.ParamDef("db.pool.acquire", {
	defVal: 10000
})
new Msa.ParamDef("db.pool.idle", {
	defVal: 30000
})
<|endoftext|>


<commit_before>var http = require('http');

var getPageData = function(title, callback){
    //this is the link format
    var link = "/starcraft2/api.php?format=json&action=query&titles="+ title + "&prop=revisions&rvprop=content";

    //here we have the variable we're going to run the callback on
    var holder;

    //these are the options for the http request
    var options = {
	host: 'wiki.teamliquid.net',
	port: 80,
	path: link
    };

    //do a get request
    http.get(options, function(resp){
	var output = '';

	//put together the output
	resp.on('data', function(chunk){
	    output += chunk;
	});

	//when we're at the end, put the object together and store it
	resp.on('end', function(){
	    holder = JSON.parse(output);
	    //console.log("In end function");
	    //console.log(resp.statusCode);
	    //console.log(holder);

	    callback(holder);
	});
    });
};

var parsePage = function(page){
    //first we split it into an array called lines
    var lines = page.split(/\r\n|\r|\n/g);
    var count = 1;
    var inBracket = false;
    var DE;
    var numPlayers;
    var result;
    var data = {};
    var bracketRE = /{{(.*)bracket$/i;

    for(i in lines){
	//if we're in a bracket
	if(bracketRD.test(lines[i])){
	    inBracket = true;
	    result = bracketRE.exec(lines[i]);
	    //check if its a standard bracket
	    if(/(\d+)(S|D)E/i.test(result[1])){
		result = /(\d+)(S|D)E/.exec(result[1]);
		if(result[2] != 'D'){
		    DE = false;
		}else{
		    DE = true;
		}
		numPlayers = result[1];
	    }
	}

	if(inBracket){
	    if(/\|R(\d+)(D|W)(\d+)race=([ztpr])/i.test(lines[i])){
		result = /\|R(\d+)(D|W)\d+race=([ztpr])/i.exec(lines[i]);
		console.log("Found Round " + result[1] + " " + result[2] + result[3] + " race: " + result[4]);
	    }
	}
	if(/{{:(.*)}}/.test(lines[i])){
		result = /{{:(.*)}}/.exec(lines[i]);
	    console.log("found link: ");
	    console.log(result[1]);
	}

    }
};

var parseGroupStage = function(lines) {
    var inGroupStage = false,
    groupStageCount = 1,
    groupStageHeadingLevel = 0,
    inGroupTable = false,
    result;

    for(i in lines){
	// If we are in a group stage section, look for a heading that could close this section
	if (inGroupStage && /^(=+).*=+$/.test(lines[i])) {
	    result = /^(=+).*=+$/.exec(lines[i]);
	    // Close the current group stage if section ends
	    // (new heading with at same level, or level closer to 1)
	    if (result[1].match(/=/g).length <= groupStageHeadingLevel) {
		groupStageCount++;
		inGroupStage = false;
		groupStageHeadingLevel = 0;
	    }
	}
	// Look for a Group Stage heading (not mandatory)
	if(/^(=+)[\s]*Group Stage.*=+$/i.test(lines[i])) {
	    result = /^(=+)[\s]*Group Stage.*=+$/i.exec(lines[i]);
	    inGroupStage = true;
	    groupStageHeadingLevel = result[1].match(/=/g).length;
	}
	// Look for a GroupTableStart line
	if(/\{\{(Template:)?GroupTableStart/i.test(lines[i])) {
	    inGroupTable = true;
	}
	if(inGroupTable){
	    if(/\{\{(Template\:)*GroupTableSlot[\s]?\|(.*)race=([ztpr])/i.test(lines[i])) {
		result = /\{\{(Template\:)*GroupTableSlot[\s]*\|.*race=([ztpr])/i.exec(lines[i]);
		console.log("Found Group Stage " + groupStageCount + " race:", result[2]);
	    }
	}
    }
};

module.exports.getPageData = getPageData;
module.exports.parsePage = parsePage;
<commit_msg>added some error checking<commit_after>var http = require('http');

var getPageData = function(title, callback){
    //this is the link format
    var link = "/starcraft2/api.php?format=json&action=query&titles="+ title + "&prop=revisions&rvprop=content";

    //here we have the variable we're going to run the callback on
    var holder;

    //these are the options for the http request
    var options = {
	host: 'wiki.teamliquid.net',
	port: 80,
	path: link
    };

    //do a get request
    http.get(options, function(resp){
	var output = '';

	//put together the output
	resp.on('data', function(chunk){
	    output += chunk;
	});

	//when we're at the end, put the object together and store it
	resp.on('end', function(){
	    holder = JSON.parse(output);
	    //console.log("In end function");
	    //console.log(resp.statusCode);
	    //console.log(holder);

	    callback(holder);
	});
    });
};

var parsePage = function(page){
    //first we split it into an array called lines
    var lines = page.split(/\r\n|\r|\n/g);

    parseBracket(lines);
    console.log("done");
    parseGroupStage(lines);
    console.log("done");

};

var parseBracket = function(lines){
    var DE;
    var numPlayers;
    var result;
    var data = {};
    var bracketRE = /{{(.*)bracket$/i;
    var inBracket = false;

    console.log("we're parsing brackets");

    for(i in lines){
	//if we're in a bracket
	if(bracketRE.test(lines[i])){
	    inBracket = true;
	    result = bracketRE.exec(lines[i]);
	    //check if its a standard bracket
	    if(/(\d+)(S|D)E/i.test(result[1])){
		result = /(\d+)(S|D)E/.exec(result[1]);
		if(result[2] != 'D'){
		    DE = false;
		}else{
		    DE = true;
		}
		numPlayers = result[1];
	    }
	}

	if(inBracket){
	    if(/\|R(\d+)(D|W)(\d+)race=([ztpr])/i.test(lines[i])){
		result = /\|R(\d+)(D|W)(\d+)race=([ztpr])/i.exec(lines[i]);
		console.log("Found Round " + result[1] + " " + result[2] + result[3] + " race: " + result[4]);
	    }
	}
	if(/{{:(.*)}}/.test(lines[i])){
		result = /{{:(.*)}}/.exec(lines[i]);
	    console.log("found link: ");
	    console.log(result[1]);
	}

    }
};

var parseGroupStage = function(lines) {
    var inGroupStage = false,
    groupStageCount = 1,
    groupStageHeadingLevel = 0,
    inGroupTable = false,
    result;

    console.log("we're parsing groups");

    for(i in lines){
	// If we are in a group stage section, look for a heading that could close this section
	if (inGroupStage && /^(=+).*=+$/.test(lines[i])) {
	    result = /^(=+).*=+$/.exec(lines[i]);
	    // Close the current group stage if section ends
	    // (new heading with at same level, or level closer to 1)
	    if (result[1].match(/=/g).length <= groupStageHeadingLevel) {
		groupStageCount++;
		inGroupStage = false;
		groupStageHeadingLevel = 0;
	    }
	}
	// Look for a Group Stage heading (not mandatory)
	if(/^(=+)[\s]*Group Stage.*=+$/i.test(lines[i])) {
	    result = /^(=+)[\s]*Group Stage.*=+$/i.exec(lines[i]);
	    inGroupStage = true;
	    groupStageHeadingLevel = result[1].match(/=/g).length;
	}
	// Look for a GroupTableStart line
	if(/\{\{(Template:)?GroupTableStart/i.test(lines[i])) {
	    inGroupTable = true;
	}
	if(inGroupTable){
	    if(/\{\{(Template\:)*GroupTableSlot[\s]?\|(.*)race=([ztpr])/i.test(lines[i])) {
		result = /\{\{(Template\:)*GroupTableSlot[\s]*\|.*race=([ztpr])/i.exec(lines[i]);
		console.log("Found Group Stage " + groupStageCount + " race:", result[2]);
	    }
	}
    }
};

module.exports.getPageData = getPageData;
module.exports.parsePage = parsePage;
<|endoftext|>