<commit_before>/*jslint sloppy: true, es5: true, nomen: true*/
/*global emit: false, getRow: false, isArray: false, log: false, provides: false, registerType: false, require: false, send: false, start: false, sum: false, toJSON: false */
// view/sheet

exports.views = {
    "listByType": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type && doc.type === "player") {
                emit([doc._id, "player", name], 1);
            } else {
                if (doc.player) {
                    emit([doc.player, doc.type, name], 1);
                }
            }
        },
        "reduce": "_count"
    },
    "listByPlayer": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type && doc.type === "player") {
                emit([doc._id, "player", name], 1);
            } else {
                if (doc.player) {
                    emit([doc.player, doc.type, name], 1);
                }
            }
        },
        "reduce": "_count"
    },
    "listTypes": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type) {
                emit([doc.type, name], 1);
            }
        },
        "reduce": "_count"
    }
};

exports.shows = {
    player: function (doc, req) {
        if (doc.type && doc.type === "player") {
            return "
" + doc.name + "
";
        }
    }
};
<commit_msg>Added filters for replication<commit_after>/*jslint sloppy: true, es5: true, nomen: true*/
/*global emit: false, getRow: false, isArray: false, log: false, provides: false, registerType: false, require: false, send: false, start: false, sum: false, toJSON: false */
// view/sheet

exports.views = {
    "listByType": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type && doc.type === "player") {
                emit([doc._id, "player", name], 1);
            } else {
                if (doc.player) {
                    emit([doc.player, doc.type, name], 1);
                }
            }
        },
        "reduce": "_count"
    },
    "listByPlayer": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type && doc.type === "player") {
                emit([doc._id, "player", name], 1);
            } else {
                if (doc.player) {
                    emit([doc.player, doc.type, name], 1);
                }
            }
        },
        "reduce": "_count"
    },
    "listTypes": {
        "map": function (doc) {
            var name = null;
            if (doc.name) {
                name = doc.name;
            }
            if (doc.type) {
                emit([doc.type, name], 1);
            }
        },
        "reduce": "_count"
    }
};

exports.shows = {
    player: function (doc, req) {
        if (doc.type && doc.type === "player") {
            return "
" + doc.name + "
";
        }
    }
};

exports.filters = {
    typedDocs: function (doc, req) {
        if (doc._deleted) {
            return true;
        }
        return !!(doc.type);
    },
    myDocs: function (doc, req) {
        if (doc._deleted) {
            return true;
        }
        if (doc.type) {
            if (doc.type === "player" && doc._id === req.query.id) {
                return true;
            }
            if (doc.type === "character" && doc.player === req.query.id) {
                return true;
            }
        }
        return false;
    }
};
<|endoftext|>


<commit_before>/*jshint multistr:true */
// Tests. Mocha/assert style. See
// http://visionmedia.github.com/mocha/
// http://nodejs.org/docs/latest/api/assert.html

var assert = require('assert');
var jsdom = require('jsdom');
var agave = require('../index.js');

var mockObject = {
  foo: 'bar',
  baz: {
    bam:'boo',
    zar:{
      zog:'victory'
    }
  },
  null:{
    'yarr':{
      'parrot':'ahoy'
    }
  }
};

// Set up a global.document with a DOM in the same way a browser has
var setupDOM = function(documentText) {
  var document = jsdom.jsdom(documentText, null, {
    features: {
      QuerySelector: true
    }
  });
  window = document.createWindow();
  ['Element','NodeList','document'].forEach(function(obj){
    global[obj] = window[obj];
  });
};

var mockHTML = ' \
 \
   \

 \
      <heading>Sample document</heading> \
      <author></author> \

Carles portland banh mi lomo twee.
 \

Narwhal bicycle rights keffiyeh beard.
 \

Pork belly beard pop-up kale chips.
 \

 \
   \
 \
';

setupDOM(mockHTML);

agave.enable('agv');

describe('Array.contains', function(){
  it('fetches the item accurately', function(){
    assert(['one','two','three'].agvcontains('two') );
  });
  it('handles missing items accurately', function(){
    assert( ! ['one','two','three'].agvcontains('notthere') );
  });
});

describe('Array.extend', function(){
  it('extends the array accurately', function(){
    assert.deepEqual([1,2,3].agvextend([4,5]), [1,2,3,4,5] );
  });
});

describe('String.contains', function(){
  it('checks for the substring accurately', function(){
    assert('elephantine'.agvcontains('tin') );
  });
  it('handles missing substrings accurately', function(){
    assert( ! 'elephantine'.agvcontains('zam') );
  });
});

describe('String.endsWith', function(){
  it('works if the string actually ends with the suffix', function(){
    assert('Hello world'.agvendsWith('world'));
  });
  it('handles trying to check if something ends in something larger than itself', function(){
    assert.equal('world'.agvendsWith('Hello world'), false);
  });
});

describe('String.startsWith', function(){
  it('works if the string actually starts with the prefix', function(){
    assert('Hello world'.agvstartsWith('Hello'));
  });
});

describe('String.repeat', function(){
  it('repeats strings accurately', function(){
    assert.equal('Hello world'.agvrepeat(3), 'Hello worldHello worldHello world');
  });
});

describe('String.reverse', function(){
  it('reverses strings accurately', function(){
    assert.equal('Hello world'.agvreverse(), 'dlrow olleH');
  });
});

describe('String.leftStrip', function(){
  it('strips from the left accurately', function(){
    assert.equal('Hello world'.agvleftStrip('Hle'), 'o world');
  });
});

describe('String.rightStrip', function(){
  it('strips from the right accurately', function(){
    assert.equal('Hello world'.agvrightStrip('ldr'), 'Hello wo');
  });
});

describe('String.rightStrip', function(){
  it('strips from the left accurately with a single character', function(){
    assert.equal('a'.agvleftStrip('a'), '');
  });
});

describe('String.strip', function(){
  it('strips from the both sides accurately', function(){
    assert.equal('Hello world'.agvstrip('Hld'), 'ello wor');
  });
});

describe('Object.getKeys', function(){
  it('fetches keys accurately', function(){
    assert.deepEqual(mockObject.agvgetKeys(), ["foo","baz","null"] );
  });
});

describe('Object.getSize', function(){
  it('counts keys accurately', function(){
    assert.equal(mockObject.agvgetSize(), 3);
  });
});

describe('Array.findItem', function(){
  it('correctly finds items that match the function', function(){
    assert.equal(['one','two','three'].agvfindItem(function(item){
      return (item === 'three');
    }), 'three');
  });
});

describe('Object.getPath', function(){
  it('returns undefined when a value is missing', function(){
    assert.equal(mockObject.agvgetPath(['foo','pineapple']), undefined);
  });
  it('returns the value when the provided keys exist', function(){
    assert.equal(mockObject.agvgetPath(['baz','zar','zog']), 'victory');
  });
  it('returns the value when the provided keys exist, even if null is on the path', function(){
    assert.equal(mockObject.agvgetPath([null,'yarr','parrot']), 'ahoy');
  });
  it('works using Unix-style paths', function(){
    assert.equal(mockObject.agvgetPath('/baz/zar/zog'), 'victory');
  });
});

describe('Agave really doesn\'t affect for loops', function(){
  it ('doesn\'t. really', function(){
    for ( var key in mockObject ) {
      assert( ! ['getKeys','getSize','getPath'].agvcontains(key) );
    }
  });
});

describe('Prefixing', function(){
  agave.enable('av');
  it('allows methods to be found under the prefix', function(){
    assert('hamparty'.avcontains('art') );
  });
});

describe('NodeList.forEach', function(){
  it('iterates over nodes properly', function(){
    var results = [];
    var paras = document.querySelectorAll('p');

    paras.avforEach(function(para){
      results.push(para.textContent)
    })
    var correctResults = [
      'Carles portland banh mi lomo twee.',
      'Narwhal bicycle rights keffiyeh beard.',
      'Pork belly beard pop-up kale chips.'
    ]
    // Just check the first 3 results as other tests may add paragraphs
    assert.deepEqual(results.slice(0,3),correctResults);
  });
});

describe('Element.createChild', function(){
  var sillyText = 'ethical messenger bag';
  var article = document.querySelector('article');
  article.agvcreateChild('p',{'id':'testpara'},sillyText);
  it('creates children with the specified attributes', function(){
    var paraCount = document.querySelector('#testpara');
    assert(paraCount);
  });
  it('creates children with the specified text', function(){
    assert(document.querySelector('#testpara').textContent === sillyText );
  });
});

describe('Element.getParents', function(){
  it('returns all parent nodes', function(){
    var ancestors = document.querySelector('heading').avgetParents();
    var results = [];
    ancestors.avforEach(function(ancestor){
      results.push(ancestor.tagName)
    })
    var correctResults = ["ARTICLE","BODY","HTML"];
    assert.deepEqual(results, correctResults);
  });
});

describe('Element.applyStyles', function(){
  it('styles elements', function(){
    var heading = document.querySelector('heading');
    heading.agvapplyStyles({'font-size':'18em'})
    assert.equal(heading.style['font-size'], '18em');
  });
});<commit_msg>Remove some tests that weren't effective - JSDom currently returns arrays instead of NodeLists - see https://github.com/tmpvar/jsdom/issues/561<commit_after>/*jshint multistr:true */
// Tests. Mocha/assert style. See
// http://visionmedia.github.com/mocha/
// http://nodejs.org/docs/latest/api/assert.html

var assert = require('assert');
var jsdom = require('jsdom');
var agave = require('../index.js');

var mockObject = {
  foo: 'bar',
  baz: {
    bam:'boo',
    zar:{
      zog:'victory'
    }
  },
  null:{
    'yarr':{
      'parrot':'ahoy'
    }
  }
};

// Set up a global.document with a DOM in the same way a browser has
var setupDOM = function(documentText) {
  var document = jsdom.jsdom(documentText, null, {
    features: {
      QuerySelector: true
    }
  });
  window = document.createWindow();
  ['Element','NodeList','document'].forEach(function(obj){
    global[obj] = window[obj];
  });
};

var mockHTML = ' \
 \
   \

 \
      <heading>Sample document</heading> \
      <author></author> \

Carles portland banh mi lomo twee.
 \

Narwhal bicycle rights keffiyeh beard.
 \

Pork belly beard pop-up kale chips.
 \

 \
   \
 \
';

setupDOM(mockHTML);

agave.enable('agv');

describe('Array.contains', function(){
  it('fetches the item accurately', function(){
    assert(['one','two','three'].agvcontains('two') );
  });
  it('handles missing items accurately', function(){
    assert( ! ['one','two','three'].agvcontains('notthere') );
  });
});

describe('Array.extend', function(){
  it('extends the array accurately', function(){
    assert.deepEqual([1,2,3].agvextend([4,5]), [1,2,3,4,5] );
  });
});

describe('String.contains', function(){
  it('checks for the substring accurately', function(){
    assert('elephantine'.agvcontains('tin') );
  });
  it('handles missing substrings accurately', function(){
    assert( ! 'elephantine'.agvcontains('zam') );
  });
});

describe('String.endsWith', function(){
  it('works if the string actually ends with the suffix', function(){
    assert('Hello world'.agvendsWith('world'));
  });
  it('handles trying to check if something ends in something larger than itself', function(){
    assert.equal('world'.agvendsWith('Hello world'), false);
  });
});

describe('String.startsWith', function(){
  it('works if the string actually starts with the prefix', function(){
    assert('Hello world'.agvstartsWith('Hello'));
  });
});

describe('String.repeat', function(){
  it('repeats strings accurately', function(){
    assert.equal('Hello world'.agvrepeat(3), 'Hello worldHello worldHello world');
  });
});

describe('String.reverse', function(){
  it('reverses strings accurately', function(){
    assert.equal('Hello world'.agvreverse(), 'dlrow olleH');
  });
});

describe('String.leftStrip', function(){
  it('strips from the left accurately', function(){
    assert.equal('Hello world'.agvleftStrip('Hle'), 'o world');
  });
});

describe('String.rightStrip', function(){
  it('strips from the right accurately', function(){
    assert.equal('Hello world'.agvrightStrip('ldr'), 'Hello wo');
  });
});

describe('String.rightStrip', function(){
  it('strips from the left accurately with a single character', function(){
    assert.equal('a'.agvleftStrip('a'), '');
  });
});

describe('String.strip', function(){
  it('strips from the both sides accurately', function(){
    assert.equal('Hello world'.agvstrip('Hld'), 'ello wor');
  });
});

describe('Object.getKeys', function(){
  it('fetches keys accurately', function(){
    assert.deepEqual(mockObject.agvgetKeys(), ["foo","baz","null"] );
  });
});

describe('Object.getSize', function(){
  it('counts keys accurately', function(){
    assert.equal(mockObject.agvgetSize(), 3);
  });
});

describe('Array.findItem', function(){
  it('correctly finds items that match the function', function(){
    assert.equal(['one','two','three'].agvfindItem(function(item){
      return (item === 'three');
    }), 'three');
  });
});

describe('Object.getPath', function(){
  it('returns undefined when a value is missing', function(){
    assert.equal(mockObject.agvgetPath(['foo','pineapple']), undefined);
  });
  it('returns the value when the provided keys exist', function(){
    assert.equal(mockObject.agvgetPath(['baz','zar','zog']), 'victory');
  });
  it('returns the value when the provided keys exist, even if null is on the path', function(){
    assert.equal(mockObject.agvgetPath([null,'yarr','parrot']), 'ahoy');
  });
  it('works using Unix-style paths', function(){
    assert.equal(mockObject.agvgetPath('/baz/zar/zog'), 'victory');
  });
});

describe('Agave really doesn\'t affect for loops', function(){
  it ('doesn\'t. really', function(){
    for ( var key in mockObject ) {
      assert( ! ['getKeys','getSize','getPath'].agvcontains(key) );
    }
  });
});

describe('Prefixing', function(){
  agave.enable('av');
  it('allows methods to be found under the prefix', function(){
    assert('hamparty'.avcontains('art') );
  });
});

describe('Element.createChild', function(){
  var sillyText = 'ethical messenger bag';
  var article = document.querySelector('article');
  article.agvcreateChild('p',{'id':'testpara'},sillyText);
  it('creates children with the specified attributes', function(){
    var paraCount = document.querySelector('#testpara');
    assert(paraCount);
  });
  it('creates children with the specified text', function(){
    assert(document.querySelector('#testpara').textContent === sillyText );
  });
});

describe('Element.applyStyles', function(){
  it('styles elements', function(){
    var heading = document.querySelector('heading');
    heading.agvapplyStyles({'font-size':'18em'})
    assert.equal(heading.style['font-size'], '18em');
  });
});<|endoftext|>


<commit_before>import test from 'ava'

test.todo('event-emitter')
<commit_msg>add a sample test<commit_after>import test from 'ava'

// module under test
import createEventEmitter from '../src/event-emitter'

test('creating an event emitter', t => {
  const subject = createEventEmitter()

  t.true('on' in subject)
  t.true('trigger' in subject)
})

<|endoftext|>


<commit_before>'use strict';

var novicell = novicell || {};

novicell.topbarRelated = novicell.topbarRelated || new function () {
    this.init = function () {

        function fixedTopbar(elementID, className, headerClass) {
            // Get the current scroll position
            var scroll = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
            var headerHeight = document.querySelector(headerClass).offsetHeight;

            if (scroll >= headerHeight + 25) {
                addClass(elementID, className);
            }
            if (scroll < headerHeight + 25) {
                removeClass(elementID, className);
            }
        }

        // Adds a class to the element
        function addClass(elementID, className) {
            var element = document.getElementById(elementID),
                classNames = document.getElementById(elementID).className;
            if (classNames.indexOf(className) == -1) {
                var el = element.className = element.className + ' ' + className;
                return el;
            }
        }

        // Removes the class and the preceding whitespace from the element
        function removeClass(elementID, className) {
            var element = document.getElementById(elementID),
                classNames = document.getElementById(elementID).className;
            if (classNames.indexOf(className) !== -1) {
                className = " " + className;
                var el = element.className = element.className.replace(className, '');
                return el;
            }
        }

        window.addEventListener('scroll', function() {
            fixedTopbar('js-topbar-related', 'sticky', '.js-header');
        }, false);
    };
}();
<commit_msg>minor fixes<commit_after>'use strict';

var novicell = novicell || {};

novicell.topbarRelated = novicell.topbarRelated || new function () {
    this.init = function () {

        function fixedTopbar(elementID, className, headerClass) {
            // Get the current scroll position
            var scroll = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
            var headerHeight = document.querySelector(headerClass).offsetHeight;

            if (scroll >= headerHeight + 25) {
                addClass(elementID, className);
            }
            if (scroll < headerHeight + 25) {
                removeClass(elementID, className);
            }
        }

        // Adds a class to the element
        function addClass(elementID, className) {
            var element = document.getElementById(elementID),
                classNames = element.className;
            if (classNames.indexOf(className) == -1) {
                classNames += (' ' + className);
                element.className = classNames;
            }
        }

        // Removes the class and the preceding whitespace from the element
        function removeClass(elementID, className) {
            var element = document.getElementById(elementID),
                classNames = element.className;
            if (classNames.indexOf(className) !== -1) {
                className = ' ' + className;
                element.className = element.className.replace(className, '');
            }
        }

        window.addEventListener('scroll', function () {
            fixedTopbar('js-topbar-related', 'sticky', '.js-header');
        }, false);
    };
}();
<|endoftext|>


<commit_before>d3.csv("dc.data.csv", function(csv){
	var data = crossfilter(csv);
	//set dimension vars
	var question_half_hour = data.dimension(function (d){
			//console.log(d.question_half_hour)
			return d.question_half_hour;
		}),
		question_weekday = data.dimension(function (d){
			return d.question_weekday;
		}),
		location_name = data.dimension(function (d){
			return d.location_name;
		}),
		patron_type = data.dimension(function(d){
			return d.patron_type;
		}),
		time_spent = data.dimension(function(d){
			return d.time_spent;
		});

	//set group vars
	var question_half_hour_group = question_half_hour.group().reduceCount(),
		question_weekday_group = question_weekday.group().reduceCount(),
		location_name_group = location_name.group().reduceCount(),
		patron_type_group = patron_type.group().reduceCount(),
		time_spent_group = time_spent.group().reduceCount();

	var question_half_hour_chart = dc.barChart("#question_half_hour")
		.width($("#question_half_hour").width())
		.height(300)
		.margins({top:10, left:50, right:10, bottom:80})
		.dimension(question_half_hour)
		.group(question_half_hour_group)
		.label(function(d){ return d.key; })
		.colors(["rgb(49, 130, 189)"])
		.elasticY(false)
		.x(d3.scale.ordinal().domain(question_half_hour_group))
        .xUnits(dc.units.ordinal)
        .yAxis().ticks(4);

	var question_weekday_chart = dc.rowChart("#question_weekday")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(question_weekday)
		.group(question_weekday_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.renderTitle(true)
		.colors(["rgb(65, 174, 118)"])
		.elasticX(true)
		.xAxis().ticks(4)
		.yAxis();

	var location_name_chart = dc.pieChart("#location_name")
		.dimension(location_name)
		.group(location_name_group)
		.radius([100])
		.innerRadius([50])
		.label(function(d){ return d.key; })
		.renderLabel(true)
		.colors(["#fdae61", "#ffffbf", "#abdda4", "#2b83ba", "#d7191c"])
		.legend(dc.legend().x(10).y(10).itemHeight(12).gap(5));

	var patron_type_chart = dc.rowChart("#patron_type")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(patron_type)
		.group(patron_type_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.colors(["rgb(240, 182, 76)"])
		.elasticX(true)
		.xAxis().ticks(4);

	var time_spent_chart = dc.rowChart("#time_spent")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(time_spent)
		.group(time_spent_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.colors(["rgb(242, 130, 110)"])
		.elasticX(true)
		.xAxis().ticks(4);

	dc.renderAll();

})
<commit_msg>j err<commit_after>d3.csv("dc.data.csv", function(csv){
	var data = crossfilter(csv);
	//set dimension vars
	var question_half_hour = data.dimension(function (d){
			//console.log(d.question_half_hour)
			return d.question_half_hour;
		}),
		question_weekday = data.dimension(function (d){
			return d.question_weekday;
		}),
		location_name = data.dimension(function (d){
			return d.location_name;
		}),
		patron_type = data.dimension(function(d){
			return d.patron_type;
		}),
		time_spent = data.dimension(function(d){
			return d.time_spent;
		});

	//set group vars
	var question_half_hour_group = question_half_hour.group().reduceCount(),
		question_weekday_group = question_weekday.group().reduceCount(),
		location_name_group = location_name.group().reduceCount(),
		patron_type_group = patron_type.group().reduceCount(),
		time_spent_group = time_spent.group().reduceCount();

	var question_half_hour_chart = dc.barChart("#question_half_hour")
		.width($("#question_half_hour").width())
		.height(300)
		.margins({top:10, left:50, right:10, bottom:80})
		.dimension(question_half_hour)
		.group(question_half_hour_group)
		.label(function(d){ return d.key; })
		.colors(["rgb(49, 130, 189)"])
		.elasticY(false)
		.x(d3.scale.ordinal().domain(question_half_hour_group))
        .xUnits(dc.units.ordinal)
        .yAxis().ticks(4);

	var question_weekday_chart = dc.rowChart("#question_weekday")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(question_weekday)
		.group(question_weekday_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.renderTitle(true)
		.colors(["rgb(65, 174, 118)"])
		.elasticX(true)
		.xAxis().ticks(4)
		.yAxis().ticks(7);

	var location_name_chart = dc.pieChart("#location_name")
		.dimension(location_name)
		.group(location_name_group)
		.radius([100])
		.innerRadius([50])
		.label(function(d){ return d.key; })
		.renderLabel(true)
		.colors(["#fdae61", "#ffffbf", "#abdda4", "#2b83ba", "#d7191c"])
		.legend(dc.legend().x(10).y(10).itemHeight(12).gap(5));

	var patron_type_chart = dc.rowChart("#patron_type")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(patron_type)
		.group(patron_type_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.colors(["rgb(240, 182, 76)"])
		.elasticX(true)
		.xAxis().ticks(4);

	var time_spent_chart = dc.rowChart("#time_spent")
		.width(250)
		.height(250)
		.margins({top:10, left:10, right:10, bottom:30})
		.dimension(time_spent)
		.group(time_spent_group)
		.label(function(d){ return d.key; })
		.title(function(d){ return d.value; })
		.colors(["rgb(242, 130, 110)"])
		.elasticX(true)
		.xAxis().ticks(4);

	dc.renderAll();

})
<|endoftext|>


<commit_before>
/******************************************
 * Set your API key here for testing
 ******************************************/
GLOBAL.apiKey = '';

/******************************************
 * Set tracking numbers here
 ******************************************/

GLOBAL.tracking = {
  ups: '1Z21E98F0314447088',
  tnt: '881232984'
};

/******************************************
 * Test files to run
 ******************************************/

var tests = [
  'track.js',
  'trackings.js',
  'couriers.js'
];

/******************************************
 * Don't touch below this!
 ******************************************/

var optimist = require('optimist');

var argv = optimist.usage('\n./tests.js OPTIONS', {
  'verbose': {
    description: 'If set, shows verbose output',
    alias: 'v',
    default: false,
    boolean: true
  }
}).argv;

// Choose appropriate reporter
var reporter;
if (argv.verbose) {
  reporter = require('nodeunit').reporters.default;

  // Add directory to each item
  for (var i=0;i<tests.length;i++) {
    tests[i] = 'test/' + tests[i];
  }

} else {
  reporter = require('nodeunit');

  // Add directory to each item
  for (var i=0;i<tests.length;i++) {
    tests[i] = __dirname + '/' + tests[i];
  }
}

if (argv.verbose) {
  reporter.run(tests, null);

} else {
  reporter.runFiles(tests);
}
<commit_msg>Added more testing sample tracking number<commit_after>/******************************************
 * Set your API key here for testing
 ******************************************/
GLOBAL.apiKey = '';

/******************************************
 * Set tracking numbers here
 ******************************************/

GLOBAL.tracking = {
  '4px': 'S0161579',
  'abf': '023471187',
  'aeroflash': '0000059S44077052000',
  'aramex': '7865103750',
  'australia-post': '60602175829091',
  'austrian-post': '1020961000000270140203',
  'bluedart': '13953569151',
  'bpost': 'CD097118257BE',
  'brazil-correios': 'RT184013321HK',
  'canada-post': 'CX152462363CA',
  'ceska-posta': 'CV018141675CZ',
  'china-ems': 'LN090239352CN',
  'china-post': 'RB638463168CN',
  'chronopost-france': 'EQ028187141AU',
  'chronopost-portugal': '09667479000266Y',
  'city-link': 'DA504809',
  'correos-de-mexico': 'EE793254021MX',
  'danmark-post': '00257059831510850052',
  'deutsch-post': 'RG363876914DE:08:26:13',
  'dhl': '4681442382',
  'dhl-benelux': 'JJD00009005823414004051',
  'dhl-germany': '320515158241',
  'dhl-global-mail': 'GM5451139750618182',
  'dhl-nl': 'JJD00009005770854017849',
  'dpd': '05167016980292',
  'dpd-poland': '0002580014936B',
  'dpd-uk': '15505994344183',
  'elta-courier': 'NZ990003254GR',
  'estafeta': '1026089369',
  'estes': '4046642666',
  'fedex': '573191403485',
  'fedex-uk': '03816601670',
  'flash-courier': '00723116936',
  'gls': '90295251672',
  'hermes': '5853112039365278',
  'hermes-de': '09222115000091',
  'hong-kong-post': 'RC878817187HK',
  'india-post': 'RN183856723IN',
  'india-post-int': 'ED246019595IN',
  'interlink-express': '15976924334370J',
  'international-seur': '6551632',
  'israel-post': 'RR295541738IL',
  'italy-sda': '2830014087448',
  'kn': 'NTG268611689',
  'korea-post': 'RR917455677KR',
  'la-poste-colissimo': 'LE027260494FR',
  'lasership': 'LH14644596',
  'malaysia-post': 'EM300414561MY',
  'malaysia-post-posdaftar': 'RR148168665MY',
  'mexico-multipack': '153600381098',
  'mrw-spain': '23000342398',
  'nacex-spain': '10223334:2844',
  'new-zealand-post': 'RR009956924NZ',
  'nova-poshta': '59000022462893',
  'oca-ar': 'QAA14251930',
  'ontrac': 'D10010608010453',
  'parcel-force': 'PBNS2194803001',
  'poczta-polska': 'CP146871488PL',
  'portugal-ctt': 'CP016017542PT',
  'portugal-seur': 'AUF-L-2090240',
  'poste-italiane': 'RT183645021HK',
  'poste-italiane-paccocelere': 'ZA123456789IT',
  'postnl': '3SRPPB1644664:4900HA',
  'ptt-posta': 'RR182174944TR',
  'red-express': '00251249',
  'rl-carriers': '051650091',
  'royal-mail': 'KF392852901GB',
  'russian-post': 'VA008900172RU',
  'sapo': 'CN030672518ZA',
  'saudi-post': 'EH001512027SA',
  'selektvracht': '3SXLDW00387',
  'sf-express': '029197190059',
  'singapore-post': 'RQ026259720SG',
  'singapore-speedpost': 'EM800039184SG',
  'siodemka': '8230007484998',
  'skynet': '238020661126',
  'spain-correos-es': 'RR453455234ES',
  'star-track': '2NX22459',
  'swiss-post': 'RY009748935CH',
  'taiwan-post': 'RA097277029TW',
  'taqbin-hk': '120012597110',
  'taqbin-sg': '120019135121',
  'thailand-post': 'RR073570309TH',
  'tnt': '880280693',
  'toll-global-express': '813081390262',
  'uk-mail': '31038770035059',
  'ukrposhta': 'RA491880118UA',
  'ups': '1Z86392WYW91844988',
  'ups-freight': '526284382',
  'ups-mi': '92748901100613553000137292',
  'usps': '9449010200828835620973',
  'yrc': '2754478706'
};

/******************************************
 * Test files to run
 ******************************************/

var tests = [
  'track.js',
  'trackings.js',
  'couriers.js'
];

/******************************************
 * Don't touch below this!
 ******************************************/

var optimist = require('optimist');

var argv = optimist.usage('\n./tests.js OPTIONS', {
  'verbose': {
    description: 'If set, shows verbose output',
    alias: 'v',
    default: false,
    boolean: true
  }
}).argv;

// Choose appropriate reporter
var reporter;
if (argv.verbose) {
  reporter = require('nodeunit').reporters.default;

  // Add directory to each item
  for (var i = 0; i < tests.length; i++) {
    tests[i] = 'test/' + tests[i];
  }

} else {
  reporter = require('nodeunit');

  // Add directory to each item
  for (var i = 0; i < tests.length; i++) {
    tests[i] = __dirname + '/' + tests[i];
  }
}

if (argv.verbose) {
  reporter.run(tests, null);

} else {
  reporter.runFiles(tests);
}
<|endoftext|>


<commit_before>import should from 'should';
import FetchModule from '../src/fetch-module/fetch-library.js';
import config from './config.js';

const fetchModule = new FetchModule(config);

describe('Fetch library', () => {

    it('Can get all', (done) => {
        fetchModule.getAll()
            .then((data) => {
                should(data).be.ok;
                data.should.be.an.array;
                data.length.should.be.above(0);
                data.forEach((val) => {
                    val.should.have.properties(['id', 'data', 'event']);
                })
                done();
            })
            .catch(done);
    });

});
<commit_msg>updated old test<commit_after>import should from 'should';
import FetchModule from '../src/fetch-module/fetch-library.js';
import config from './config.js';

const fetchModule = new FetchModule(config);

describe('Fetch library', () => {

    it('Can get all', (done) => {
        fetchModule.getAll()
            .then((data) => {
                should(data).be.ok;
                data.should.be.an.array;
                data.length.should.be.above(0);
                data.forEach((val) => {
                    val.should.have.properties(['id', 'event_data', 'event_name']);
                })
                done();
            })
            .catch(done);
    });

});
<|endoftext|>


<commit_before>/*
Hi! If you're reading this then you're probably not me. That means that you also
probably don't understand how this works.I'll try and help you understand. There
are a bunch of comments scattered around that should help you along. I would
suggest that you read through this code carefully; the things that you have to
change manually should be clearly marked, However, if they aren't everything
should be explained below.
THINGS TO ENTER IN YOURSELF:
* The date and time that the raffle ends.
* The number of days after the raffle that you want the meter content to change.
* The link to the Google Sheet that the information is being stored in.
* The column that the status of the books is recorded in.
* The column that the number of tickets sold is recorded in.
* The characters that are used to symbolize each state of the tickets. (If you
change it for whatever reason, please also change the comment to match.)
*(maybe) The amount "sold" is multiplied by 5 to create the money variable. (It's
explained more at the specific place in the code.)
* The message that automatically shows up when the raffle ends. (I'm still iffy
on what I've written there.)
* The year that it currently is. (I'm sure there's a way to dynamically change
that but I don't feel like coding that right now.)

WHAT THIS CODE DOES:
It pulls information from a Google Spreadsheet and counts the number of 0s, 1s,
2s, 3s, and 4s there are in a specified column. The number of 0s is counted as
the number of book that haven't been touched; the 1s count as the books that are
checked out being sold; the 2s count as the number of full books that have been
sold; the 3s mark original partial books; and the 4s only appear after 3s to
mark that row as the rest of the above partial book. These numbers are then
turned into statistics that get displayed on the website as the progress bar.
There are two different ways it gets displayed based on if large-raffle-meter is
true in the front matter of the page.

If you're *still* confused after reading all of this please contact either
Tim Scalzo, Ekaterina Vasilyeva (22vasilyevaek@fpsct.org) or Giselle Koo (gisellegk@gmail.com) for
help.

Thank you for taking the time to read this.
~~~~~~-Tim Scalzo
*/

google.load('visualization', 1.0);
// For info on how `Date()` is formatted, check out http://www.w3schools.com/jsref/jsref_obj_date.asp
var raffleDeadline = new Date(2019, 12, 19, 17, 30, 0); // Make sure to set this to the proper deadline.
var millisecondsLeft = raffleDeadline - new Date();
var numDays = Math.ceil(millisecondsLeft/86400000);

var container; // entire progress bar
var soldTag; // blue
var outTag; // yellow
var rafflePage; // if large raffle meter, it must be on raffle page (that's how it works right now, don't judge me)

$( document ).ready(function() {
  // Does not do this stuff until all the elements on the page are done loading.
  if ($("#raffle-meter-container").length > 0) { // Length is the number of elements with this id.
    container = "#raffle-meter-container";
    soldTag = ".halfStyle.hs-vertical-third:before";
    outTag = ".halfStyle.hs-vertical-third:after";
    rafflePage = true;
  } else {
    container = "#raffle-meter-container-s";
    soldTag = "#raffle-meter-sold";
    outTag = "#raffle-meter-out";
    rafflePage = false;
  }

  if (numDays >= -2 && true) { // The true is there so that you can manually turn this off before the two days after if you want.

    google.setOnLoadCallback(get_data);
    function get_data() {
      var opts = {sendMethod: 'auto'};                // Make sure to manually change the link to the proper Google Sheet.
      var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1uU3Pm3NhyHXzpDaZV4B0mEFYhUn8C339FmJRpNbMkeo/edit#gid=0', opts);
      query.setQuery('SELECT G, H'); // Make sure to manually select the proper columns. (Use SQL if you need to do something more complex.)
      query.send(handleQueryResponse);
      // Note: The function will only run when the page is loaded.

      if (numDays <= 1 && numDays > (1/24)) { // Makes function automatically refresh every minute when there's only a day left
        setTimeout(function(){ get_data(); }, 60000);
      } else if (numDays <= (1/24)) { // Makes function automatically refresh every 100 miliseconds when there's only an hour left
        setTimeout(function(){ get_data(); }, 100);
      }
    }
    function handleQueryResponse(response){ // This function uses the data gathered to make percents and send them to the meter
      if (response.isError()){ // This makes sure you get a usable error message (in case anything goes wrong).
        console.log('Error: ' + response.getMessage() + ' ' + response.getDetailedMessage());
        return;
      }
      var data = response.getDataTable();
      data.Nf.splice(0, 2); // Removes the first row that has stuff that we don't want.
      var base = 0;
      var sold = 0;
      var out = 0;
      for (var i = 0; i < data.getNumberOfRows(); i++){ // The i++ adds 1 to 'i' after it goes through the loop once.
      /* Key for what the values mean: */
      // 0 = untouched (base)
      // 1 = checked out (out)
      // 2 = full book sold (sold)
      // 3 = original partial book (sold & out)
      // 4 = other partial books; only happens after a 3 (sold & out)
      /* Key for what the columns are for: */
      // 0 = Status of book
      // 1 = Number of tickets sold from book
        if (data.getValue(i,0) == 0) { // Checks for 0 in row 'i'.
          base += 20; // Adds 20 to the base if ^^^^ is true.
        } else if(data.getValue(i,0) == 1) { // Checks for 1 in row 'i'.
          out += 20; // Adds 20 to the out if ^^^^ is true.
        } else if(data.getValue(i,0) == 3) { // Checks for 3 in row 'i'.
          sold += data.getValue(i,1); // Adds value in second column to the sold if ^^^^ is true.
          out += (20 - data.getValue(i,1)); // Adds the amount left in the book to the out.
        } else if(data.getValue(i,0) == 4) { // Checks for 4 in row 'i'.
          sold += data.getValue(i,1); // Shouldn't be total sold from book (it should be how much they just sold).
          out -= data.getValue(i,1); // Removes the amount sold from the out. (Because it's not out anymore, it just got sold.)
        } else if(data.getValue(i,0) == 2) { // Checks for a 2 in row 'i'.
          sold += 20; // Adds 20 to sold if the entire book is sold.
        }
      /*
      In this loop, 'i' is used as the row number. As long as 'i' is less than the number of rows there are, the loop keeps going.
      It goes through and checks row 'i' to see if the number in it matches 0, 1, 2, 3 or 4. If there's anything other than those
      numbers it ignores it.
      */
      }

      var soldPercent = sold / (sold + out + base) * 100; // Divides the amount sold by the total and makes it into percent form.
      var outPercent = (out + sold) / (sold + out + base) * 100;

      if (rafflePage) {
        $('').appendTo('head'); // Sets the soldTag's width to the soldPercent
        $('').appendTo('head'); // Sets the outTag's width to the outPercent
      } else {
        $(soldTag).css('width', soldPercent + '%'); // Sets the soldTag's width to the soldPercent
        $(outTag).css('width', outPercent + '%'); // Sets the outTag's width to the outPercent
      }

      // For text
      var money = sold * 5; // Each 1 in sold is a ticket. When I made this each ticket was worth $5.00; change this if that changes.
      var soldPercentString = soldPercent.toString(); // Turns the double into a string.
      var soldPercentShort = "";
      if (soldPercent < 10) { // When the percent is less than 10,
        soldPercentShort = soldPercentString.substring(0, 4); // ensures there's only 2 decimal places.
      } else { // When the percent is more than 10,
        soldPercentShort = soldPercentString.substring(0, 5); // ensures there's only 2 decimal places.
      }

      var timeLeft; // Generates the phrase that is the time left.
      if (numDays > 1) { // 1 day
        timeLeft = numDays + " days left";
      } else if (millisecondsLeft > 3600000) { // 1 hour
        var hoursLeft = Math.round(millisecondsLeft / 3600000);
        if (hoursLeft > 1) {
          timeLeft = hoursLeft + " hours left";
        } else {
          timeLeft = hoursLeft + " hour left";
        }
      } else if (millisecondsLeft > 0) { // 0 minutes
        var minutesLeft = Math.round(millisecondsLeft / 60000);
        if (minutesLeft > 1) {
          timeLeft = minutesLeft + " minutes left";
        } else {
          timeLeft = minutesLeft + " minute left";
        }
      } else { // no time left
        timeLeft = "There's no time left!";
      }
      $("#percent").html("Tickets sold: " + soldPercentShort + "% | $" + money.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " earned | "+ timeLeft);
      if (!rafflePage) {
        $("#percent").append(" | About the raffle >>");
      }
    }

  // This will run if you change the true to a false; it'll also change if the days after the raffle exceeds two.
  } else {
    var deliberateSoldPercent = 3.56; // Set this number manually.
    var deliberateMoney = 4500; // Set this number manually.

    if (rafflePage) {
      $('').appendTo('head'); // Sets the soldTag's width to the deliberateSoldPercent
    } else {
      $(soldTag).css('width', deliberateSoldPercent + '%'); // Sets the soldTag's width to the deliberateSoldPercent
    }
    $("#percent").html("Our " + raffleDeadline.getFullYear() + " raffle has ended! | Tickets sold: " + deliberateSoldPercent + "% | $" + deliberateMoney.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " earned");
    if (!rafflePage) {
      $("#percent").append(" | Winners >>");
    } else {
      // This changes the line of info to not include the tickets checked out
      $('#progress-info').html("Blue: Tickets sold | White: Tickets not sold");
    }
  }
});
<commit_msg>Fixing raffle meter<commit_after>/*
Hi! If you're reading this then you're probably not me. That means that you also
probably don't understand how this works.I'll try and help you understand. There
are a bunch of comments scattered around that should help you along. I would
suggest that you read through this code carefully; the things that you have to
change manually should be clearly marked, However, if they aren't everything
should be explained below.
THINGS TO ENTER IN YOURSELF:
* The date and time that the raffle ends.
* The number of days after the raffle that you want the meter content to change.
* The link to the Google Sheet that the information is being stored in.
* The column that the status of the books is recorded in.
* The column that the number of tickets sold is recorded in.
* The characters that are used to symbolize each state of the tickets. (If you
change it for whatever reason, please also change the comment to match.)
*(maybe) The amount "sold" is multiplied by 5 to create the money variable. (It's
explained more at the specific place in the code.)
* The message that automatically shows up when the raffle ends. (I'm still iffy
on what I've written there.)
* The year that it currently is. (I'm sure there's a way to dynamically change
that but I don't feel like coding that right now.)

WHAT THIS CODE DOES:
It pulls information from a Google Spreadsheet and counts the number of 0s, 1s,
2s, 3s, and 4s there are in a specified column. The number of 0s is counted as
the number of book that haven't been touched; the 1s count as the books that are
checked out being sold; the 2s count as the number of full books that have been
sold; the 3s mark original partial books; and the 4s only appear after 3s to
mark that row as the rest of the above partial book. These numbers are then
turned into statistics that get displayed on the website as the progress bar.
There are two different ways it gets displayed based on if large-raffle-meter is
true in the front matter of the page.

If you're *still* confused after reading all of this please contact either
Tim Scalzo, Ekaterina Vasilyeva (22vasilyevaek@fpsct.org) or Giselle Koo (gisellegk@gmail.com) for
help.

Thank you for taking the time to read this.
~~~~~~-Tim Scalzo
*/

google.load('visualization', 1.0);
// For info on how `Date()` is formatted, check out http://www.w3schools.com/jsref/jsref_obj_date.asp
var raffleDeadline = new Date(2019, 12, 19, 17, 30, 0); // Make sure to set this to the proper deadline.
var millisecondsLeft = raffleDeadline - new Date();
var numDays = Math.ceil(millisecondsLeft/86400000);

var container; // entire progress bar
var soldTag; // blue
var outTag; // yellow
var rafflePage; // if large raffle meter, it must be on raffle page (that's how it works right now, don't judge me)

$( document ).ready(function() {
  // Does not do this stuff until all the elements on the page are done loading.
  if ($("#raffle-meter-container").length > 0) { // Length is the number of elements with this id.
    container = "#raffle-meter-container";
    soldTag = ".halfStyle.hs-vertical-third:before";
    outTag = ".halfStyle.hs-vertical-third:after";
    rafflePage = true;
  } else {
    container = "#raffle-meter-container-s";
    soldTag = "#raffle-meter-sold";
    outTag = "#raffle-meter-out";
    rafflePage = false;
  }

  if (numDays >= -2 && false) { // The true is there so that you can manually turn this off before the two days after if you want.

    google.setOnLoadCallback(get_data);
    function get_data() {
      var opts = {sendMethod: 'auto'};                // Make sure to manually change the link to the proper Google Sheet.
      var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1uU3Pm3NhyHXzpDaZV4B0mEFYhUn8C339FmJRpNbMkeo/edit#gid=0', opts);
      query.setQuery('SELECT G, H'); // Make sure to manually select the proper columns. (Use SQL if you need to do something more complex.)
      query.send(handleQueryResponse);
      // Note: The function will only run when the page is loaded.

      if (numDays <= 1 && numDays > (1/24)) { // Makes function automatically refresh every minute when there's only a day left
        setTimeout(function(){ get_data(); }, 60000);
      } else if (numDays <= (1/24)) { // Makes function automatically refresh every 100 miliseconds when there's only an hour left
        setTimeout(function(){ get_data(); }, 100);
      }
    }
    function handleQueryResponse(response){ // This function uses the data gathered to make percents and send them to the meter
      if (response.isError()){ // This makes sure you get a usable error message (in case anything goes wrong).
        console.log('Error: ' + response.getMessage() + ' ' + response.getDetailedMessage());
        return;
      }
      var data = response.getDataTable();
      data.Nf.splice(0, 2); // Removes the first row that has stuff that we don't want.
      var base = 0;
      var sold = 0;
      var out = 0;
      for (var i = 0; i < data.getNumberOfRows(); i++){ // The i++ adds 1 to 'i' after it goes through the loop once.
      /* Key for what the values mean: */
      // 0 = untouched (base)
      // 1 = checked out (out)
      // 2 = full book sold (sold)
      // 3 = original partial book (sold & out)
      // 4 = other partial books; only happens after a 3 (sold & out)
      /* Key for what the columns are for: */
      // 0 = Status of book
      // 1 = Number of tickets sold from book
        if (data.getValue(i,0) == 0) { // Checks for 0 in row 'i'.
          base += 20; // Adds 20 to the base if ^^^^ is true.
        } else if(data.getValue(i,0) == 1) { // Checks for 1 in row 'i'.
          out += 20; // Adds 20 to the out if ^^^^ is true.
        } else if(data.getValue(i,0) == 3) { // Checks for 3 in row 'i'.
          sold += data.getValue(i,1); // Adds value in second column to the sold if ^^^^ is true.
          out += (20 - data.getValue(i,1)); // Adds the amount left in the book to the out.
        } else if(data.getValue(i,0) == 4) { // Checks for 4 in row 'i'.
          sold += data.getValue(i,1); // Shouldn't be total sold from book (it should be how much they just sold).
          out -= data.getValue(i,1); // Removes the amount sold from the out. (Because it's not out anymore, it just got sold.)
        } else if(data.getValue(i,0) == 2) { // Checks for a 2 in row 'i'.
          sold += 20; // Adds 20 to sold if the entire book is sold.
        }
      /*
      In this loop, 'i' is used as the row number. As long as 'i' is less than the number of rows there are, the loop keeps going.
      It goes through and checks row 'i' to see if the number in it matches 0, 1, 2, 3 or 4. If there's anything other than those
      numbers it ignores it.
      */
      }

      var soldPercent = sold / (sold + out + base) * 100; // Divides the amount sold by the total and makes it into percent form.
      var outPercent = (out + sold) / (sold + out + base) * 100;

      if (rafflePage) {
        $('').appendTo('head'); // Sets the soldTag's width to the soldPercent
        $('').appendTo('head'); // Sets the outTag's width to the outPercent
      } else {
        $(soldTag).css('width', soldPercent + '%'); // Sets the soldTag's width to the soldPercent
        $(outTag).css('width', outPercent + '%'); // Sets the outTag's width to the outPercent
      }

      // For text
      var money = sold * 5; // Each 1 in sold is a ticket. When I made this each ticket was worth $5.00; change this if that changes.
      var soldPercentString = soldPercent.toString(); // Turns the double into a string.
      var soldPercentShort = "";
      if (soldPercent < 10) { // When the percent is less than 10,
        soldPercentShort = soldPercentString.substring(0, 4); // ensures there's only 2 decimal places.
      } else { // When the percent is more than 10,
        soldPercentShort = soldPercentString.substring(0, 5); // ensures there's only 2 decimal places.
      }

      var timeLeft; // Generates the phrase that is the time left.
      if (numDays > 1) { // 1 day
        timeLeft = numDays + " days left";
      } else if (millisecondsLeft > 3600000) { // 1 hour
        var hoursLeft = Math.round(millisecondsLeft / 3600000);
        if (hoursLeft > 1) {
          timeLeft = hoursLeft + " hours left";
        } else {
          timeLeft = hoursLeft + " hour left";
        }
      } else if (millisecondsLeft > 0) { // 0 minutes
        var minutesLeft = Math.round(millisecondsLeft / 60000);
        if (minutesLeft > 1) {
          timeLeft = minutesLeft + " minutes left";
        } else {
          timeLeft = minutesLeft + " minute left";
        }
      } else { // no time left
        timeLeft = "There's no time left!";
      }
      $("#percent").html("Tickets sold: " + soldPercentShort + "% | $" + money.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " earned | "+ timeLeft);
      if (!rafflePage) {
        $("#percent").append(" | About the raffle >>");
      }
    }

  // This will run if you change the true to a false; it'll also change if the days after the raffle exceeds two.
  } else {
    var deliberateSoldPercent = 31.87; // Set this number manually.
    var deliberateMoney = 5100; // Set this number manually.

    if (rafflePage) {
      $('').appendTo('head'); // Sets the soldTag's width to the deliberateSoldPercent
    } else {
      $(soldTag).css('width', deliberateSoldPercent + '%'); // Sets the soldTag's width to the deliberateSoldPercent
    }
    $("#percent").html("Our " + raffleDeadline.getFullYear() + " still goes on! | Tickets sold: " + deliberateSoldPercent + "% | $" + deliberateMoney.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " earned");
    if (!rafflePage) {
      $("#percent").append(" | See the prizes >>");
    } else {
      // This changes the line of info to not include the tickets checked out
      $('#progress-info').html("Blue: Tickets sold | White: Tickets not sold");
    }
  }
});
<|endoftext|>


<commit_before><commit_msg>Upgraded Geocomplete Jquery plugin.<commit_after><|endoftext|>


<commit_before>import BlackSail from './battle/ship/black-sail-part';
import Cannon from './battle/ship/cannon-part';
import Debris from './battle/debris';
import Highscore from './battle/highscore';
import Message from './battle/message';
import PirateShip from './battle/pirate-ship';
import Trader from './battle/trader';
import {SpinGlitch, StormGlitch, LowResGlitch, MirrorGlitch} from './battle/glitches';
import Whale from './battle/whale';

export default class Battle {
    constructor(game, withTutorial = false) {
        this.withTutorial = withTutorial;
        this.cannonBalls = [];
        this.debris = [];
        this.traders = [];
        this.effects = [];
        this.pirateShip = new PirateShip(this);
        this.updateOccupied();
        this.addRandomDebris();
        this.provisions = 10;
        this.score = 0;
        this.animationStep = 0;
        this.glitchActive = false;
        this.spin = 0;
        this.stormFactor = 0;
        this.highscore = new Highscore();

        if (withTutorial) {
            this.message = new Message(this, [
                'Hunt traders crossing the Glitchy Sea and keep your provisions in check.',
                'Use left and right arrow keys to steer, T to toggle music.'
            ]);
        }

        this.rewards = [
            [8, () => { this.provisions += 2 }],
            [4, () => BlackSail],
            [2, () => Cannon],
            [1, () => {
                if (!this.glitchActive) {
                    const createGlitch = [
                        () => new SpinGlitch(this),
                        () => new StormGlitch(this),
                        () => new LowResGlitch(game.screen),
                        () => new MirrorGlitch(game.screen)
                    ][Math.random() * 2 | 0];
                    this.effects.push(createGlitch());
                }
            }],
        ];
        this.rewardSum = this.rewards.reduce((sum, [part]) => part + sum, 0);
    }

    update(game) {
        this.effects.forEach(effect => { effect.update() });
        this.effects = this.effects.filter(effect => effect.alive);

        if (!this.pirateShip.alive) {
            if (game.input.hasKey(32)) {
                game.input.handleKey(32);
                game.startBattle();
            }
            return;
        }

        if (this.message) {
            if (game.input.hasKey(32)) {
                this.message.continue();
                game.input.handleKey(32);
            }
            if (!this.message.alive) {
                this.message = null
            }
            return;
        }

        this.applyKeyInput(game.input);

        this.pirateShip.update();

        this.traders = this.traders.filter((trader) => {
            trader.update();
            return trader.alive;
        });

        this.debris = this.debris.filter((debris) => debris.alive);

        this.cannonBalls = this.cannonBalls.filter((cannonBall) => {
            cannonBall.update();
            return cannonBall.alive;
        });
        this.traders = this.traders.filter((trader) => trader.alive);

        this.updateOccupied();
        if (this.isOccupied(this.pirateShip.parts[0].position.x, this.pirateShip.parts[0].position.y)) {
            this.pirateShip.die(true, ['You’re shark food now. Let that sink in… or']);
            return;
        }
        if (this.traders.length == 0) {
            this.addTrader();
        }

        this.provisions = Math.max(this.provisions - .01, 0);
        if (this.provisions < 1) {
            this.pirateShip.die(false, ['Without any food left you’re too weak to fight the rats taking over now.']);
        }

        this.animationStep++;
    }

    draw(screen) {
        for (let x = 15; x--;) {
            for (let y = 15; y--;) {
                const colorModifier = (this.getOffset(x, y) - this.getOffset(x + 1, y + 1)) * 2 - Math.random() * 2;
                screen.addPolygon(
                    x, y,
                    (x + y) + 1,
                    [
                        0, 0 + this.getOffset(x, y),
                        20, 10 + this.getOffset(x, y + 1),
                        0, 20 + this.getOffset(x + 1, y + 1),
                        -20, 10 + this.getOffset(x + 1, y)
                    ],
                    this.pirateShip.alive ? 'hsl(160,60%,'+(47-colorModifier)+'%)' : 'hsl(160,0%,'+(70-colorModifier)+'%)'
                );
            }
        }

        this.debris.forEach(function (entity) {
            entity.draw(screen);
        });

        this.cannonBalls.forEach(function (entity) {
            entity.draw(screen);
        });

        this.traders.forEach(function (entity) {
            entity.draw(screen);
        });

        this.pirateShip.draw(screen);

        screen.ctx.save();
        screen.ctx.translate(400, 310);
        screen.ctx.rotate(this.spin);
        screen.ctx.translate(-400, -310);

        screen.ctx.font = '20px Times New Roman, serif';
        screen.ctx.textAlign = 'left';
        screen.ctx.save();
        screen.ctx.translate(165, 256);
        screen.ctx.rotate(-Math.PI/2.8);
        screen.ctx.transform(1, 0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Provisions: ' + (this.provisions | 0), 0, 0);
        screen.ctx.restore();

        screen.ctx.save();
        screen.ctx.translate(520, 200);
        screen.ctx.rotate(Math.PI/2.8);
        screen.ctx.transform(1, -0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Gold: ' + this.score, 0, 0);
        screen.ctx.restore();

        screen.ctx.save();
        screen.ctx.translate(659, 360);
        screen.ctx.rotate(Math.PI - Math.PI/2.8);
        screen.ctx.transform(1, 0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Highest Gold: ' + this.highscore.get(), 0, 0);
        screen.ctx.restore();

        screen.drawPolygons();

        screen.ctx.restore();

        if (this.message) {
            this.message.draw(screen);
        }
    }

    getOffset(x, y) {
        return (1 - this.stormFactor) * 2 * Math.sin(x + y - this.animationStep / 8) + this.stormFactor * (4 - 12 * Math.random());
    }

    updateOccupied() {
        this.occupied = [];
        this.pirateShip.addOccupied(this.occupied);
        this.traders.forEach((trader) => {
            trader.addOccupied(this.occupied);
        });
    }

    isOccupied(x, y) {
        return this.occupied.some((o) => {
            return x == o.x && y == o.y;
        });
    }

    addRandomDebris() {
        let x, y;
        do {
            x = Math.random() * 14 + 1 | 0;
            y = Math.random() * 14 + 1 | 0;
        } while (this.isOccupied(x, y));

        this.debris.push(new Debris(this, x, y));
    }

    addTrader() {
        let x, y;
        do {
            x = Math.random() * 14 + 1 | 0;
            y = Math.random() < .5 ? 0 : 15;
            if (Math.random() < .5) {
                [x, y] = [y, x];
            }
        } while (this.isOccupied(x, y));

        const direction = {
            x: x == 0 ? 1 : x == 15 ? -1 : 0,
            y: y == 0 ? 1 : y == 15 ? -1 : 0
        };

        this.traders.push(new (Math.random() < .2 ? Whale : Trader)(this, {x: x, y: y}, direction));
    }

    isOutOfBounds(position) {
        if (!position) {
            return true;
        }
        if (position.x < 0 || position.x > 15) {
            return true;
        }
        if (position.y < 0 || position.y > 15) {
            return true;
        }
        return false;
    };

    applyKeyInput(input) {
        this.pirateShip.shooting = input.hasKey(32);

        if (input.hasKey(37)) {
            input.handleKey(37);
            this.pirateShip.nextDirection = {x: -this.pirateShip.direction.y, y: this.pirateShip.direction.x};
        }
        if (input.hasKey(39)) {
            input.handleKey(39);
            this.pirateShip.nextDirection = {x: this.pirateShip.direction.y, y: -this.pirateShip.direction.x};
        }
    }

    rollReward() {
        let r = Math.random() * this.rewardSum;

        for (const [part, callback] of this.rewards) {
            if (r < part) {
                return callback();
            }
            r -= part;
        }
    }

    increaseScore(delta) {
        this.score += delta;
        this.highscore.update(this.score);
    }
}
<commit_msg>fix UI color<commit_after>import BlackSail from './battle/ship/black-sail-part';
import Cannon from './battle/ship/cannon-part';
import Debris from './battle/debris';
import Highscore from './battle/highscore';
import Message from './battle/message';
import PirateShip from './battle/pirate-ship';
import Trader from './battle/trader';
import {SpinGlitch, StormGlitch, LowResGlitch, MirrorGlitch} from './battle/glitches';
import Whale from './battle/whale';

export default class Battle {
    constructor(game, withTutorial = false) {
        this.withTutorial = withTutorial;
        this.cannonBalls = [];
        this.debris = [];
        this.traders = [];
        this.effects = [];
        this.pirateShip = new PirateShip(this);
        this.updateOccupied();
        this.addRandomDebris();
        this.provisions = 10;
        this.score = 0;
        this.animationStep = 0;
        this.glitchActive = false;
        this.spin = 0;
        this.stormFactor = 0;
        this.highscore = new Highscore();

        if (withTutorial) {
            this.message = new Message(this, [
                'Hunt traders crossing the Glitchy Sea and keep your provisions in check.',
                'Use left and right arrow keys to steer, T to toggle music.'
            ]);
        }

        this.rewards = [
            [8, () => { this.provisions += 2 }],
            [4, () => BlackSail],
            [2, () => Cannon],
            [1, () => {
                if (!this.glitchActive) {
                    const createGlitch = [
                        () => new SpinGlitch(this),
                        () => new StormGlitch(this),
                        () => new LowResGlitch(game.screen),
                        () => new MirrorGlitch(game.screen)
                    ][Math.random() * 2 | 0];
                    this.effects.push(createGlitch());
                }
            }],
        ];
        this.rewardSum = this.rewards.reduce((sum, [part]) => part + sum, 0);
    }

    update(game) {
        this.effects.forEach(effect => { effect.update() });
        this.effects = this.effects.filter(effect => effect.alive);

        if (!this.pirateShip.alive) {
            if (game.input.hasKey(32)) {
                game.input.handleKey(32);
                game.startBattle();
            }
            return;
        }

        if (this.message) {
            if (game.input.hasKey(32)) {
                this.message.continue();
                game.input.handleKey(32);
            }
            if (!this.message.alive) {
                this.message = null
            }
            return;
        }

        this.applyKeyInput(game.input);

        this.pirateShip.update();

        this.traders = this.traders.filter((trader) => {
            trader.update();
            return trader.alive;
        });

        this.debris = this.debris.filter((debris) => debris.alive);

        this.cannonBalls = this.cannonBalls.filter((cannonBall) => {
            cannonBall.update();
            return cannonBall.alive;
        });
        this.traders = this.traders.filter((trader) => trader.alive);

        this.updateOccupied();
        if (this.isOccupied(this.pirateShip.parts[0].position.x, this.pirateShip.parts[0].position.y)) {
            this.pirateShip.die(true, ['You’re shark food now. Let that sink in… or']);
            return;
        }
        if (this.traders.length == 0) {
            this.addTrader();
        }

        this.provisions = Math.max(this.provisions - .01, 0);
        if (this.provisions < 1) {
            this.pirateShip.die(false, ['Without any food left you’re too weak to fight the rats taking over now.']);
        }

        this.animationStep++;
    }

    draw(screen) {
        for (let x = 15; x--;) {
            for (let y = 15; y--;) {
                const colorModifier = (this.getOffset(x, y) - this.getOffset(x + 1, y + 1)) * 2 - Math.random() * 2;
                screen.addPolygon(
                    x, y,
                    (x + y) + 1,
                    [
                        0, 0 + this.getOffset(x, y),
                        20, 10 + this.getOffset(x, y + 1),
                        0, 20 + this.getOffset(x + 1, y + 1),
                        -20, 10 + this.getOffset(x + 1, y)
                    ],
                    this.pirateShip.alive ? 'hsl(160,60%,'+(47-colorModifier)+'%)' : 'hsl(160,0%,'+(70-colorModifier)+'%)'
                );
            }
        }

        this.debris.forEach(function (entity) {
            entity.draw(screen);
        });

        this.cannonBalls.forEach(function (entity) {
            entity.draw(screen);
        });

        this.traders.forEach(function (entity) {
            entity.draw(screen);
        });

        this.pirateShip.draw(screen);

        screen.ctx.save();
        screen.ctx.translate(400, 310);
        screen.ctx.rotate(this.spin);
        screen.ctx.translate(-400, -310);

        screen.ctx.fillStyle = '#630';

        screen.ctx.font = '20px Times New Roman, serif';
        screen.ctx.textAlign = 'left';
        screen.ctx.save();
        screen.ctx.translate(165, 256);
        screen.ctx.rotate(-Math.PI/2.8);
        screen.ctx.transform(1, 0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Provisions: ' + (this.provisions | 0), 0, 0);
        screen.ctx.restore();

        screen.ctx.save();
        screen.ctx.translate(520, 200);
        screen.ctx.rotate(Math.PI/2.8);
        screen.ctx.transform(1, -0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Gold: ' + this.score, 0, 0);
        screen.ctx.restore();

        screen.ctx.save();
        screen.ctx.translate(659, 360);
        screen.ctx.rotate(Math.PI - Math.PI/2.8);
        screen.ctx.transform(1, 0.8, 0, 1, 0, 0);
        screen.ctx.fillText('Highest Gold: ' + this.highscore.get(), 0, 0);
        screen.ctx.restore();

        screen.drawPolygons();

        screen.ctx.restore();

        if (this.message) {
            this.message.draw(screen);
        }
    }

    getOffset(x, y) {
        return (1 - this.stormFactor) * 2 * Math.sin(x + y - this.animationStep / 8) + this.stormFactor * (4 - 12 * Math.random());
    }

    updateOccupied() {
        this.occupied = [];
        this.pirateShip.addOccupied(this.occupied);
        this.traders.forEach((trader) => {
            trader.addOccupied(this.occupied);
        });
    }

    isOccupied(x, y) {
        return this.occupied.some((o) => {
            return x == o.x && y == o.y;
        });
    }

    addRandomDebris() {
        let x, y;
        do {
            x = Math.random() * 14 + 1 | 0;
            y = Math.random() * 14 + 1 | 0;
        } while (this.isOccupied(x, y));

        this.debris.push(new Debris(this, x, y));
    }

    addTrader() {
        let x, y;
        do {
            x = Math.random() * 14 + 1 | 0;
            y = Math.random() < .5 ? 0 : 15;
            if (Math.random() < .5) {
                [x, y] = [y, x];
            }
        } while (this.isOccupied(x, y));

        const direction = {
            x: x == 0 ? 1 : x == 15 ? -1 : 0,
            y: y == 0 ? 1 : y == 15 ? -1 : 0
        };

        this.traders.push(new (Math.random() < .2 ? Whale : Trader)(this, {x: x, y: y}, direction));
    }

    isOutOfBounds(position) {
        if (!position) {
            return true;
        }
        if (position.x < 0 || position.x > 15) {
            return true;
        }
        if (position.y < 0 || position.y > 15) {
            return true;
        }
        return false;
    };

    applyKeyInput(input) {
        this.pirateShip.shooting = input.hasKey(32);

        if (input.hasKey(37)) {
            input.handleKey(37);
            this.pirateShip.nextDirection = {x: -this.pirateShip.direction.y, y: this.pirateShip.direction.x};
        }
        if (input.hasKey(39)) {
            input.handleKey(39);
            this.pirateShip.nextDirection = {x: this.pirateShip.direction.y, y: -this.pirateShip.direction.x};
        }
    }

    rollReward() {
        let r = Math.random() * this.rewardSum;

        for (const [part, callback] of this.rewards) {
            if (r < part) {
                return callback();
            }
            r -= part;
        }
    }

    increaseScore(delta) {
        this.score += delta;
        this.highscore.update(this.score);
    }
}
<|endoftext|>


<commit_before>// openSeadragonApp: Defines the Angular application ==================================================================================================================================
var openSeadragonApp = angular.module('openSeadragonApp', ['ERMrest']);

// ERMrestService: A service for operations that deal with the ERMrest db =============================================================================================================
openSeadragonApp.service('ERMrestService', ['ermrestClientFactory', '$http', function(ermrestClientFactory, $http) {
    // Get a reference to the ERMrestService service
    var self = this;

    // Parse Chaise url to determine required parameters to find the requested entity
    this.path = window.location.hash;
    this.params = this.path.split('/');
    this.catalogId = this.params[0].substring(1);
    this.schemaName = this.params[1].split(':')[0];
    this.tableName = this.params[1].split(':')[1];
    this.entityId = this.params[2].split('=')[1];

    // The name of the table where the annotations are stored — currently 'roi'
    this.annotationTableName = 'annotation';
    this.anatomyTableName = 'anatomy';

    var ERMREST_ENDPOINT = window.location.origin + '/ermrest/catalog/';
    if (chaiseConfig['ermrestLocation'] != null) {
        ERMREST_ENDPOINT = chaiseConfig['ermrestLocation'] + '/ermrest/catalog';
    }

    var client = ermrestClientFactory.getClient(window.location.origin + '/ermrest', null);
    var catalog = client.getCatalog(1);

    // Returns a Schema object from ERMrest
    this.getSchema = function getSchema() {
        return catalog.introspect().then(function(schemas) {
            return schemas[self.schemaName];
        });
    };

    // Returns the uri value from a row in rbk:image (filtered by the id found in URL)
    this.getEntity = function getEntity() {
        return this.getSchema().then(function(schema) {
            var table = schema.getTable(self.tableName);
            var filteredTable = table.getFilteredTable(["id=" + self.entityId]);
            return filteredTable.getEntities().then(function(rows) {
                return rows[0].data.uri;
            });
        });
    };

    this.createAnnotation = function createAnnotation(annotation) {
        if (annotation.anatomy === "") {
            annotation.anatomy = null;
        }

        annotation = [{
            "image_id": self.entityId,
            "anatomy": annotation.anatomy,
            "context_uri": annotation.context_uri,
            "coords": [
                annotation.shape.geometry.x,
                annotation.shape.geometry.y,
                annotation.shape.geometry.width,
                annotation.shape.geometry.height
            ],
            "description": annotation.description
        }];
        return this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            return table.createEntity(annotation, ['id', 'author', 'created']).then(function(response) {
                return response;
            });
        });
    };

    this.updateAnnotation = function updateAnnotation(annotation) {
        if (annotation.anatomy === "") {
            annotation.anatomy = null;
        }

        var editedAnnotation = [{
            "id": annotation.id,
            "image_id": self.entityId,
            "author": null,
            "created": annotation.created,
            "context_uri": annotation.context_uri,
            "coords": annotation.coords,
            "description": annotation.description,
            "anatomy": annotation.anatomy
        }];
        var entityPath = ERMREST_ENDPOINT + this.catalogId + '/entity/' + this.schemaName + ':' + this.annotationTableName;
        return $http.put(entityPath, editedAnnotation);
    };

    this.getAnnotations = function getAnnotations() {
        var annotations = [];
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            var filteredTable = table.getFilteredTable(["image_id=" + self.entityId]);
            return filteredTable.getEntities().then(function(rows) {
                if (rows.length > 0) {
                    return Promise.all(rows.map(function(row) {
                        annotations.push(row.data);
                    }));
                } else {
                    console.log('No annotations found for this image.')
                }
            });
        });
        return annotations;
    };

    this.deleteAnnotation = function deleteAnnotation(annotation) {
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            var filteredTable = table.getFilteredTable(["id=" + annotation.id]);
            return filteredTable.getEntities().then(function(rows) {
                rows[0].delete();
            });
        });
    };

    this.getAnatomies = function getAnatomies() {
        var anatomies = [];
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.anatomyTableName);
            table.getEntities().then(function(rows) {
                if (rows.length > 0) {
                    return Promise.all(rows.map(function(row) {
                        anatomies.push(row.data.term);
                    }));
                } else {
                    return rows;
                }
            });
        });
        return anatomies;
    };
}]);

// MainController: An Angular controller to update the view ===========================================================================================================================
openSeadragonApp.controller('MainController', ['$scope', '$window', 'ERMrestService', function($scope, $window, ERMrestService) {
    $scope.annotations = ERMrestService.getAnnotations();
    $scope.anatomies = ERMrestService.getAnatomies(); // An array of elements, where each element is a string of an anatomy term
    $scope.viewerSource = null; // The source URL of the iframe/viewer
    $scope.viewerReady = false; // True if viewer (OpenSeadragon/Annotorious) has finished setup
    $scope.viewer = null; // A reference to the iframe window

    $scope.highlightedAnnotation = null; // Track which annotation is highlighted/centered right now

    $scope.createMode = false; // True if user is currently creating a new annotation
    $scope.newAnnotation = null; // Holds the data for a new annotation as it's being created

    $scope.editedAnnotation = null; // Track which one is being edited right now; used to show/hide the right UI elements depending on which one is being edited.
    $scope.originalAnnotation = null; // Holds the original contents of annotation in the event that a user cancels an edit

    // Fetch uri from image table to load OpenSeadragon
    ERMrestService.getEntity().then(function(uri) {
        // TODO: Remove me after pushing to vm-wide version of OpenSeadragon ///////////////
        // Splicing in my ~jessie directory in here so it redirects to my own version of OpenSeadragon and not the VM-wide version..
        uri = uri.substring(0, 34) + '~jessie/' + uri.substring(34);
        ///////////////////////////////////////////////////////////////////////////////////
        // Initialize OpenSeadragon with the uri
        $scope.viewerSource = uri;
    });

    // Listen for events from OpenSeadragon/iframe
    $window.addEventListener('message', function(event) {
        if (event.origin === window.location.origin) {
            var data = event.data;
            var messageType = data.messageType;
            switch (messageType) {
                case 'annotoriousReady':
                    $scope.viewerReady = data.content;
                    if ($scope.viewerReady) {
                        $scope.viewer = window.frames[0];
                        $scope.viewer.postMessage({messageType: 'loadAnnotations', content: $scope.annotations}, window.location.origin);
                    }
                    break;
                case 'annotationDrawn':
                    $scope.newAnnotation = {
                        description: null,
                        shape: data.content.shape
                    };
                    $scope.$apply(function() {
                        $scope.createMode = true;
                    });
                    break;
                default:
                    console.log('Invalid message type. No action performed.');
            }
        } else {
            console.log('Invalid event origin. Event origin: ', origin, '. Expected origin: ', window.location.origin);
        }
    });

    $scope.setHighlightedAnnotation = function setHighlightedAnnotation(annotationId) {
        $scope.highlightedAnnotation = annotationId;
    };

    $scope.highlightAnnotation = function highlightAnnotation(annotation) {
        $scope.viewer.postMessage({messageType: 'highlightAnnotation', content: annotation}, window.location.origin);
    };

    // Activates the drawing selector tool in Annotorious
    $scope.drawAnnotation = function drawAnnotation() {
        $scope.viewer.postMessage({messageType: 'drawAnnotation'}, window.location.origin);
    };

    // Stop creating an annotation: Hides the forms used to create an annotation in Chaise and Annotorious
    $scope.cancelAnnotationCreation = function cancelAnnotationCreation() {
        $scope.createMode = false;
        $scope.viewer.postMessage({messageType: 'cancelAnnotationCreation'}, window.location.origin);
    };

    // Given the new annotation data, it creates the annotation in Annotorious and ERMrest
    $scope.createAnnotation = function createAnnotation(newAnnotation) {
        $scope.createMode = false;
        newAnnotation.context_uri = $scope.viewerSource;
        // Create new annotation in ERMrest
        return ERMrestService.createAnnotation(newAnnotation).then(function(response) {
            if (response.length > 0) {
                newAnnotation = response[0];
                // Send new annotation to Annotorious
                $scope.viewer.postMessage({messageType: 'createAnnotation', content: newAnnotation}, window.location.origin);
                // Add new annotation to controller scope
                $scope.annotations.push(newAnnotation);
                $scope.newAnnotation = null;
                return newAnnotation;
            } else {
                return response;
            }
        });
    }

    // Sets the selected annotation to edit mode
    $scope.editAnnotation = function editAnnotation(annotation) {
        $scope.editedAnnotation = annotation.id;
        $scope.originalAnnotation = annotation;
    };

    // Stop editing an annotation
    $scope.cancelAnnotationEdit = function cancelAnnotationEdit(annotation) {
        $scope.editedAnnotation = null;
        annotation = $scope.originalAnnotation;
    };

    // Given the updated annotation data, it updates the annotation in Annotorious and ERMrest
    $scope.saveAnnotation = function saveAnnotation(annotation) {
        $scope.editedAnnotation = null;
        $scope.viewer.postMessage({messageType: 'updateAnnotation', content: annotation}, window.location.origin);
        ERMrestService.updateAnnotation(annotation);
    }

    $scope.deleteAnnotation = function deleteAnnotation(annotation) {
        var index = $scope.annotations.indexOf(annotation);
        $scope.annotations.splice(index, 1);
        $scope.viewer.postMessage({messageType: 'deleteAnnotation', content: annotation}, window.location.origin);
        ERMrestService.deleteAnnotation(annotation);
    };
}]);

// Trusted: A filter that tells Angular when a url is trusted =========================================================================================================================
openSeadragonApp.filter('trusted', ['$sce', function($sce) {
    return function(url) {
        return $sce.trustAsResourceUrl(url);
    };
}]);

// Capitalize: A filter that capitalizes the first character for each word in a string ================================================================================================
openSeadragonApp.filter('capitalize', function() {
    return function(input, all) {
        var regex = (all) ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/;
        return (!!input) ? input.replace(regex, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        }) : '';
    }
});

// Refreshes page when the window's hash changes
window.onhashchange = function() {
    if (window.location.hash != '#undefined') {
        location.reload();
    } else {
        history.replaceState("", document.title, window.location.pathname);
        location.reload();
    }
    function goBack() {
        window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
        window.location.lasthash.pop();
    }
}
<commit_msg>Update annotations with author field instead of null<commit_after>// openSeadragonApp: Defines the Angular application ==================================================================================================================================
var openSeadragonApp = angular.module('openSeadragonApp', ['ERMrest']);

// ERMrestService: A service for operations that deal with the ERMrest db =============================================================================================================
openSeadragonApp.service('ERMrestService', ['ermrestClientFactory', '$http', function(ermrestClientFactory, $http) {
    // Get a reference to the ERMrestService service
    var self = this;

    // Parse Chaise url to determine required parameters to find the requested entity
    this.path = window.location.hash;
    this.params = this.path.split('/');
    this.catalogId = this.params[0].substring(1);
    this.schemaName = this.params[1].split(':')[0];
    this.tableName = this.params[1].split(':')[1];
    this.entityId = this.params[2].split('=')[1];

    // The name of the table where the annotations are stored — currently 'roi'
    this.annotationTableName = 'annotation';
    this.anatomyTableName = 'anatomy';

    var ERMREST_ENDPOINT = window.location.origin + '/ermrest/catalog/';
    if (chaiseConfig['ermrestLocation'] != null) {
        ERMREST_ENDPOINT = chaiseConfig['ermrestLocation'] + '/ermrest/catalog';
    }

    var client = ermrestClientFactory.getClient(window.location.origin + '/ermrest', null);
    var catalog = client.getCatalog(1);

    // Returns a Schema object from ERMrest
    this.getSchema = function getSchema() {
        return catalog.introspect().then(function(schemas) {
            return schemas[self.schemaName];
        });
    };

    // Returns the uri value from a row in rbk:image (filtered by the id found in URL)
    this.getEntity = function getEntity() {
        return this.getSchema().then(function(schema) {
            var table = schema.getTable(self.tableName);
            var filteredTable = table.getFilteredTable(["id=" + self.entityId]);
            return filteredTable.getEntities().then(function(rows) {
                return rows[0].data.uri;
            });
        });
    };

    this.createAnnotation = function createAnnotation(annotation) {
        if (annotation.anatomy === "") {
            annotation.anatomy = null;
        }

        annotation = [{
            "image_id": self.entityId,
            "anatomy": annotation.anatomy,
            "context_uri": annotation.context_uri,
            "coords": [
                annotation.shape.geometry.x,
                annotation.shape.geometry.y,
                annotation.shape.geometry.width,
                annotation.shape.geometry.height
            ],
            "description": annotation.description
        }];
        return this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            return table.createEntity(annotation, ['id', 'author', 'created']).then(function(response) {
                return response;
            });
        });
    };

    this.updateAnnotation = function updateAnnotation(annotation) {
        if (annotation.anatomy === "") {
            annotation.anatomy = null;
        }

        var editedAnnotation = [{
            "id": annotation.id,
            "image_id": self.entityId,
            "author": annotation.author,
            "created": annotation.created,
            "context_uri": annotation.context_uri,
            "coords": annotation.coords,
            "description": annotation.description,
            "anatomy": annotation.anatomy
        }];
        var entityPath = ERMREST_ENDPOINT + this.catalogId + '/entity/' + this.schemaName + ':' + this.annotationTableName;
        return $http.put(entityPath, editedAnnotation);
    };

    this.getAnnotations = function getAnnotations() {
        var annotations = [];
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            var filteredTable = table.getFilteredTable(["image_id=" + self.entityId]);
            return filteredTable.getEntities().then(function(rows) {
                if (rows.length > 0) {
                    return Promise.all(rows.map(function(row) {
                        annotations.push(row.data);
                    }));
                } else {
                    console.log('No annotations found for this image.')
                }
            });
        });
        return annotations;
    };

    this.deleteAnnotation = function deleteAnnotation(annotation) {
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.annotationTableName);
            var filteredTable = table.getFilteredTable(["id=" + annotation.id]);
            return filteredTable.getEntities().then(function(rows) {
                rows[0].delete();
            });
        });
    };

    this.getAnatomies = function getAnatomies() {
        var anatomies = [];
        this.getSchema().then(function(schema) {
            var table = schema.getTable(self.anatomyTableName);
            table.getEntities().then(function(rows) {
                if (rows.length > 0) {
                    return Promise.all(rows.map(function(row) {
                        anatomies.push(row.data.term);
                    }));
                } else {
                    return rows;
                }
            });
        });
        return anatomies;
    };
}]);

// MainController: An Angular controller to update the view ===========================================================================================================================
openSeadragonApp.controller('MainController', ['$scope', '$window', 'ERMrestService', function($scope, $window, ERMrestService) {
    $scope.annotations = ERMrestService.getAnnotations();
    $scope.anatomies = ERMrestService.getAnatomies(); // An array of elements, where each element is a string of an anatomy term
    $scope.viewerSource = null; // The source URL of the iframe/viewer
    $scope.viewerReady = false; // True if viewer (OpenSeadragon/Annotorious) has finished setup
    $scope.viewer = null; // A reference to the iframe window

    $scope.highlightedAnnotation = null; // Track which annotation is highlighted/centered right now

    $scope.createMode = false; // True if user is currently creating a new annotation
    $scope.newAnnotation = null; // Holds the data for a new annotation as it's being created

    $scope.editedAnnotation = null; // Track which one is being edited right now; used to show/hide the right UI elements depending on which one is being edited.
    $scope.originalAnnotation = null; // Holds the original contents of annotation in the event that a user cancels an edit

    // Fetch uri from image table to load OpenSeadragon
    ERMrestService.getEntity().then(function(uri) {
        // TODO: Remove me after pushing to vm-wide version of OpenSeadragon ///////////////
        // Splicing in my ~jessie directory in here so it redirects to my own version of OpenSeadragon and not the VM-wide version..
        uri = uri.substring(0, 34) + '~jessie/' + uri.substring(34);
        ///////////////////////////////////////////////////////////////////////////////////
        // Initialize OpenSeadragon with the uri
        $scope.viewerSource = uri;
        console.log($scope.annotations);
    });

    // Listen for events from OpenSeadragon/iframe
    $window.addEventListener('message', function(event) {
        if (event.origin === window.location.origin) {
            var data = event.data;
            var messageType = data.messageType;
            switch (messageType) {
                case 'annotoriousReady':
                    $scope.viewerReady = data.content;
                    if ($scope.viewerReady) {
                        $scope.viewer = window.frames[0];
                        $scope.viewer.postMessage({messageType: 'loadAnnotations', content: $scope.annotations}, window.location.origin);
                    }
                    break;
                case 'annotationDrawn':
                    $scope.newAnnotation = {
                        description: null,
                        shape: data.content.shape
                    };
                    $scope.$apply(function() {
                        $scope.createMode = true;
                    });
                    break;
                default:
                    console.log('Invalid message type. No action performed.');
            }
        } else {
            console.log('Invalid event origin. Event origin: ', origin, '. Expected origin: ', window.location.origin);
        }
    });

    $scope.setHighlightedAnnotation = function setHighlightedAnnotation(annotationId) {
        $scope.highlightedAnnotation = annotationId;
    };

    $scope.highlightAnnotation = function highlightAnnotation(annotation) {
        $scope.viewer.postMessage({messageType: 'highlightAnnotation', content: annotation}, window.location.origin);
    };

    // Activates the drawing selector tool in Annotorious
    $scope.drawAnnotation = function drawAnnotation() {
        $scope.viewer.postMessage({messageType: 'drawAnnotation'}, window.location.origin);
    };

    // Stop creating an annotation: Hides the forms used to create an annotation in Chaise and Annotorious
    $scope.cancelAnnotationCreation = function cancelAnnotationCreation() {
        $scope.createMode = false;
        $scope.viewer.postMessage({messageType: 'cancelAnnotationCreation'}, window.location.origin);
    };

    // Given the new annotation data, it creates the annotation in Annotorious and ERMrest
    $scope.createAnnotation = function createAnnotation(newAnnotation) {
        $scope.createMode = false;
        newAnnotation.context_uri = $scope.viewerSource;
        // Create new annotation in ERMrest
        return ERMrestService.createAnnotation(newAnnotation).then(function(response) {
            if (response.length > 0) {
                newAnnotation = response[0];
                // Send new annotation to Annotorious
                $scope.viewer.postMessage({messageType: 'createAnnotation', content: newAnnotation}, window.location.origin);
                // Add new annotation to controller scope
                $scope.annotations.push(newAnnotation);
                $scope.newAnnotation = null;
                return newAnnotation;
            } else {
                return response;
            }
        });
    }

    // Sets the selected annotation to edit mode
    $scope.editAnnotation = function editAnnotation(annotation) {
        $scope.editedAnnotation = annotation.id;
        $scope.originalAnnotation = annotation;
    };

    // Stop editing an annotation
    $scope.cancelAnnotationEdit = function cancelAnnotationEdit(annotation) {
        $scope.editedAnnotation = null;
        annotation = $scope.originalAnnotation;
    };

    // Given the updated annotation data, it updates the annotation in Annotorious and ERMrest
    $scope.saveAnnotation = function saveAnnotation(annotation) {
        $scope.editedAnnotation = null;
        $scope.viewer.postMessage({messageType: 'updateAnnotation', content: annotation}, window.location.origin);
        ERMrestService.updateAnnotation(annotation);
    }

    $scope.deleteAnnotation = function deleteAnnotation(annotation) {
        var index = $scope.annotations.indexOf(annotation);
        $scope.annotations.splice(index, 1);
        $scope.viewer.postMessage({messageType: 'deleteAnnotation', content: annotation}, window.location.origin);
        ERMrestService.deleteAnnotation(annotation);
    };
}]);

// Filters ============================================================================================================================================================================
// Trusted: A filter that tells Angular when a url is trusted
openSeadragonApp.filter('trusted', ['$sce', function($sce) {
    return function(url) {
        return $sce.trustAsResourceUrl(url);
    };
}]);

// Capitalize: A filter that capitalizes the first character for each word in a string
openSeadragonApp.filter('capitalize', function() {
    return function(input, all) {
        var regex = (all) ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/;
        return (!!input) ? input.replace(regex, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        }) : '';
    }
});

// Refreshes page when the window's hash changes
window.onhashchange = function() {
    if (window.location.hash != '#undefined') {
        location.reload();
    } else {
        history.replaceState("", document.title, window.location.pathname);
        location.reload();
    }
    function goBack() {
        window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
        window.location.lasthash.pop();
    }
}
<|endoftext|>