<commit_before>module( "rules" );

test( "rules() - internal - input", function() {
	var element = $( "#firstname" );

	$( "#testForm1" ).validate();

	deepEqual( element.rules(), { required: true, minlength: 2 } );
} );

test( "rules(), ignore method:false", function() {
	var element = $( "#firstnamec" );

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: { required: false, minlength: 2 }
		}
	} );

	deepEqual( element.rules(), { minlength: 2 } );
} );

test( "rules() HTML5 required (no value)", function() {
	var element = $( "#testForm11text1" );

	$( "#testForm11" ).validate();

	deepEqual( element.rules(), { required: true } );
} );

test( "rules() - internal - select", function() {
	var element = $( "#meal" );

	$( "#testForm3" ).validate();

	deepEqual( element.rules(), { required: true } );
} );

test( "rules() - external", function() {
	var element = $( "#text1" );

	$( "#form" ).validate( {
		rules: {
			action: { date: true, min: 5 }
		}
	} );

	deepEqual( element.rules(), { date: true, min: 5 } );
} );

test( "rules() - external - complete form", function() {
	expect( 1 );

	var methods = $.extend( {}, $.validator.methods ),
		messages = $.extend( {}, $.validator.messages ),
		v;

	$.validator.addMethod( "verifyTest", function() {
		ok( true, "method executed" );
		return true;
	} );
	v = $( "#form" ).validate( {
		rules: {
			action: { verifyTest: true }
		}
	} );
	v.form();

	$.validator.methods = methods;
	$.validator.messages = messages;
} );

test( "rules() - internal - input", function() {
	var element = $( "#form8input" );

	$( "#testForm8" ).validate();

	deepEqual( element.rules(), { required: true, number: true, rangelength: [ 2, 8 ] } );
} );

test( "rules(), merge min/max to range, minlength/maxlength to rangelength", function() {
	jQuery.validator.autoCreateRanges = true;

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: {
				min: -15,
				max: 0
			},
			lastname: {
				minlength: 0,
				maxlength: 10
			}
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { range: [ -15, 0 ] } );
	deepEqual( $( "#lastnamec" ).rules(), { rangelength: [ 0, 10 ] } );

	jQuery.validator.autoCreateRanges = false;
} );

test( "rules(), guarantee that required is at front", function() {
	$( "#testForm1" ).validate();
	var v = $( "#v2" ).validate();
	$( "#subformRequired" ).validate();
	function flatRules( element ) {
		var result = [];
		jQuery.each( $( element ).rules(), function( key ) { result.push( key ); } );
		return result.join( " " );
	}
	equal( flatRules( "#firstname" ), "required minlength" );
	equal( flatRules( "#v2-i6" ), "required minlength maxlength" );
	equal( flatRules( "#co_name" ), "required maxlength" );

	QUnit.reset();
	jQuery.validator.autoCreateRanges = true;
	v = $( "#v2" ).validate();
	equal( flatRules( "#v2-i6" ), "required rangelength" );

	$( "#subformRequired" ).validate( {
		rules: {
			co_name: "required"
		}
	} );
	$( "#co_name" ).removeClass();
	equal( flatRules( "#co_name" ), "required maxlength" );
	jQuery.validator.autoCreateRanges = false;
} );

test( "rules(), evaluate dynamic parameters", function() {
	expect( 2 );

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: {
				min: function( element ) {
					equal( $( "#firstnamec" )[ 0 ], element );
					return 12;
				}
			}
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { min: 12 } );
} );

test( "rules(), class and attribute combinations", function() {

	$.validator.addMethod( "customMethod1", function() {
		return false;
	}, "" );
	$.validator.addMethod( "customMethod2", function() {
		return false;
	}, "" );

	$( "#v2" ).validate( {
		rules: {
			"v2-i7": {
				required: true,
				minlength: 2,
				customMethod: true
			}
		}
	} );

	deepEqual( $( "#v2-i1" ).rules(), { required: true } );
	deepEqual( $( "#v2-i2" ).rules(), { required: true, email: true } );
	deepEqual( $( "#v2-i3" ).rules(), { url: true } );
	deepEqual( $( "#v2-i4" ).rules(), { required: true, minlength: 2 } );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, minlength: 2, maxlength: 5, customMethod1: "123" } );
	jQuery.validator.autoCreateRanges = true;
	deepEqual( $( "#v2-i5" ).rules(), { required: true, customMethod1: "123", rangelength: [ 2, 5 ] } );
	deepEqual( $( "#v2-i6" ).rules(), { required: true, customMethod2: true, rangelength: [ 2, 5 ] } );
	jQuery.validator.autoCreateRanges = false;
	deepEqual( $( "#v2-i7" ).rules(), { required: true, minlength: 2, customMethod: true } );

	delete $.validator.methods.customMethod1;
	delete $.validator.messages.customMethod1;
	delete $.validator.methods.customMethod2;
	delete $.validator.messages.customMethod2;
} );

test( "rules(), dependency checks", function() {
	var v = $( "#testForm1clean" ).validate( {
			rules: {
				firstnamec: {
					min: {
						param: 5,
						depends: function( el ) {
							return ( /^a/ ).test( $( el ).val() );
						}
					}
				},
				lastname: {
					max: {
						param: 12
					},
					email: {
						depends: function() { return true; }
					}
				}
			}
		} ),
		rules = $( "#firstnamec" ).rules();

	equal( v.objectLength( rules ), 0 );

	$( "#firstnamec" ).val( "ab" );
	deepEqual( $( "#firstnamec" ).rules(), { min: 5 } );

	deepEqual( $( "#lastnamec" ).rules(), { max: 12, email: true } );
} );

test( "rules(), add and remove", function() {
	$.validator.addMethod( "customMethod1", function() {
		return false;
	}, "" );
	$( "#v2" ).validate();
	$( "#v2-i5" ).removeClass( "required" ).removeAttr( "minlength maxlength" );
	deepEqual( $( "#v2-i5" ).rules(), { customMethod1: "123" } );

	$( "#v2-i5" ).addClass( "required" ).attr( {
		minlength: 2,
		maxlength: 5
	} );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, minlength: 2, maxlength: 5, customMethod1: "123" } );

	$( "#v2-i5" ).addClass( "email" ).attr( { min: 5 } );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, email: true, minlength: 2, maxlength: 5, min: 5, customMethod1: "123" } );

	$( "#v2-i5" ).removeClass( "required email" ).removeAttr( "minlength maxlength customMethod1 min" );
	deepEqual( $( "#v2-i5" ).rules(), {} );

	delete $.validator.methods.customMethod1;
	delete $.validator.messages.customMethod1;
} );

test( "rules(), add and remove static rules", function() {

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: "required date"
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { required: true, date: true } );

	$( "#firstnamec" ).rules( "remove", "date" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true } );
	$( "#firstnamec" ).rules( "add", "email" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true, email: true } );

	$( "#firstnamec" ).rules( "remove", "required" );
	deepEqual( $( "#firstnamec" ).rules(), { email: true } );

	deepEqual( $( "#firstnamec" ).rules( "remove" ), { email: true } );
	deepEqual( $( "#firstnamec" ).rules(), {} );

	$( "#firstnamec" ).rules( "add", "required email" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true, email: true } );

	deepEqual( $( "#lastnamec" ).rules(), {} );
	$( "#lastnamec" ).rules( "add", "required" );
	$( "#lastnamec" ).rules( "add", {
		minlength: 2
	} );
	deepEqual( $( "#lastnamec" ).rules(), { required: true, minlength: 2 } );

	var removedRules = $( "#lastnamec" ).rules( "remove", "required email" );
	deepEqual( $( "#lastnamec" ).rules(), { minlength: 2 } );
	$( "#lastnamec" ).rules( "add", removedRules );
	deepEqual( $( "#lastnamec" ).rules(), { required: true, minlength: 2 } );
} );

test( "rules(), add messages", function() {
	$( "#firstnamec" ).attr( "title", null );
	var v = $( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: "required"
		}
	} );
	$( "#testForm1clean" ).valid();
	$( "#firstnamec" ).valid();
	deepEqual( v.settings.messages.firstname, undefined );

	$( "#firstnamec" ).rules( "add", {
		messages: {
			required: "required"
		}
	} );

	$( "#firstnamec" ).valid();
	deepEqual( v.errorList[ 0 ] && v.errorList[ 0 ].message, "required" );

	$( "#firstnamec" ).val( "test" );
	$( "#firstnamec" ).valid();
	equal( v.errorList.length, 0 );
} );

test( "rules(), rangelength attribute as array", function() {
	$( "#testForm13" ).validate();
	deepEqual( $( "#cars-select" ).rules(), {
		required: true,
		rangelength: [ 2, 3 ]
	} );
} );

test( "rules(), normalizer", function() {
	var username = $( "#usernamec" ),
		urlc = $( "#urlc" ),
		lastname = $( "#lastnamec" ),
		v;

	username.val( "\t\t \r" );
	urlc.val( "" );

	v = $( "#testForm1clean" ).validate( {
		rules: {
			username: {
				required: true,

				// Using the normalizer to trim the value of the element
				// before validating it.
				normalizer: function( value ) {
					equal( this, username[ 0 ], "`this` in the normalizer should be the username element." );

					// Trim the value of the input
					return $.trim( value );
				}
			},
			urlc: {
				required: true,
				url: true,

				// Using the normalizer to append https:// if it's not
				// present on the input value
				normalizer: function( value ) {
					equal( this, urlc[ 0 ], "`this` in the normalizer should be the urlc element." );

					var url = value;

					// Check if it doesn't start with http:// or https:// or ftp://
					if ( url && url.substr( 0, 7 ) !== "http://" &&
						url.substr( 0, 8 ) !== "https://" &&
						url.substr( 0, 6 ) !== "ftp://" ) {

						// Then prefix with http:// or even https://
						url = "https://" + url;
					}

					// Return the new url
					return url;
				}
			},
			lastname: {
				required: true,

				// Using the normalizer to trim the value of the element
				// before validating it.
				normalizer: function( value ) {
					equal( this, lastname[ 0 ], "`this` in the normalizer should be the lastname element." );

					// Return null in order to make sure a exception is thrown
					// when normalizer returns a non string value.
					value = null;

					return value;
				}
			}
		}
	} );

	// Validate only the username and the url elements.
	username.valid();
	equal( v.invalidElements()[ 0 ], username[ 0 ], "The username should be invalid" );

	urlc.valid();
	equal( v.invalidElements()[ 0 ], urlc[ 0 ], "The url should be invalid" );

	equal( v.numberOfInvalids(), 2, "There is two invalid elements" );

	username.val( "something" );
	urlc.val( "google.com" );

	username.trigger( "keyup" );
	urlc.trigger( "keyup" );

	equal( v.numberOfInvalids(), 0, "All elements are valid" );
	equal( v.size(), 0, "All elements are valid" );

	// Validate the lastname element, which will throw an exception
	throws( function() {
		v.check( lastname[ 0 ] );
	}, function( err ) {
		return err.name === "TypeError" && err.message === "The normalizer should return a string value.";
	}, "This should throw a TypeError exception." );
} );
<commit_msg>Tests: Calling .rules() on an empty jQuery object results in an error.<commit_after>module( "rules" );

test( "rules() - internal - input", function() {
	var element = $( "#firstname" );

	$( "#testForm1" ).validate();

	deepEqual( element.rules(), { required: true, minlength: 2 } );
} );

test( "rules(), ignore method:false", function() {
	var element = $( "#firstnamec" );

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: { required: false, minlength: 2 }
		}
	} );

	deepEqual( element.rules(), { minlength: 2 } );
} );

test( "rules() HTML5 required (no value)", function() {
	var element = $( "#testForm11text1" );

	$( "#testForm11" ).validate();

	deepEqual( element.rules(), { required: true } );
} );

test( "rules() - internal - select", function() {
	var element = $( "#meal" );

	$( "#testForm3" ).validate();

	deepEqual( element.rules(), { required: true } );
} );

test( "rules() - external", function() {
	var element = $( "#text1" );

	$( "#form" ).validate( {
		rules: {
			action: { date: true, min: 5 }
		}
	} );

	deepEqual( element.rules(), { date: true, min: 5 } );
} );

test( "rules() - external - complete form", function() {
	expect( 1 );

	var methods = $.extend( {}, $.validator.methods ),
		messages = $.extend( {}, $.validator.messages ),
		v;

	$.validator.addMethod( "verifyTest", function() {
		ok( true, "method executed" );
		return true;
	} );
	v = $( "#form" ).validate( {
		rules: {
			action: { verifyTest: true }
		}
	} );
	v.form();

	$.validator.methods = methods;
	$.validator.messages = messages;
} );

test( "rules() - internal - input", function() {
	var element = $( "#form8input" );

	$( "#testForm8" ).validate();

	deepEqual( element.rules(), { required: true, number: true, rangelength: [ 2, 8 ] } );
} );

test( "rules(), merge min/max to range, minlength/maxlength to rangelength", function() {
	jQuery.validator.autoCreateRanges = true;

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: {
				min: -15,
				max: 0
			},
			lastname: {
				minlength: 0,
				maxlength: 10
			}
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { range: [ -15, 0 ] } );
	deepEqual( $( "#lastnamec" ).rules(), { rangelength: [ 0, 10 ] } );

	jQuery.validator.autoCreateRanges = false;
} );

test( "rules(), guarantee that required is at front", function() {
	$( "#testForm1" ).validate();
	var v = $( "#v2" ).validate();
	$( "#subformRequired" ).validate();
	function flatRules( element ) {
		var result = [];
		jQuery.each( $( element ).rules(), function( key ) { result.push( key ); } );
		return result.join( " " );
	}
	equal( flatRules( "#firstname" ), "required minlength" );
	equal( flatRules( "#v2-i6" ), "required minlength maxlength" );
	equal( flatRules( "#co_name" ), "required maxlength" );

	QUnit.reset();
	jQuery.validator.autoCreateRanges = true;
	v = $( "#v2" ).validate();
	equal( flatRules( "#v2-i6" ), "required rangelength" );

	$( "#subformRequired" ).validate( {
		rules: {
			co_name: "required"
		}
	} );
	$( "#co_name" ).removeClass();
	equal( flatRules( "#co_name" ), "required maxlength" );
	jQuery.validator.autoCreateRanges = false;
} );

test( "rules(), evaluate dynamic parameters", function() {
	expect( 2 );

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: {
				min: function( element ) {
					equal( $( "#firstnamec" )[ 0 ], element );
					return 12;
				}
			}
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { min: 12 } );
} );

test( "rules(), class and attribute combinations", function() {

	$.validator.addMethod( "customMethod1", function() {
		return false;
	}, "" );
	$.validator.addMethod( "customMethod2", function() {
		return false;
	}, "" );

	$( "#v2" ).validate( {
		rules: {
			"v2-i7": {
				required: true,
				minlength: 2,
				customMethod: true
			}
		}
	} );

	deepEqual( $( "#v2-i1" ).rules(), { required: true } );
	deepEqual( $( "#v2-i2" ).rules(), { required: true, email: true } );
	deepEqual( $( "#v2-i3" ).rules(), { url: true } );
	deepEqual( $( "#v2-i4" ).rules(), { required: true, minlength: 2 } );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, minlength: 2, maxlength: 5, customMethod1: "123" } );
	jQuery.validator.autoCreateRanges = true;
	deepEqual( $( "#v2-i5" ).rules(), { required: true, customMethod1: "123", rangelength: [ 2, 5 ] } );
	deepEqual( $( "#v2-i6" ).rules(), { required: true, customMethod2: true, rangelength: [ 2, 5 ] } );
	jQuery.validator.autoCreateRanges = false;
	deepEqual( $( "#v2-i7" ).rules(), { required: true, minlength: 2, customMethod: true } );

	delete $.validator.methods.customMethod1;
	delete $.validator.messages.customMethod1;
	delete $.validator.methods.customMethod2;
	delete $.validator.messages.customMethod2;
} );

test( "rules(), dependency checks", function() {
	var v = $( "#testForm1clean" ).validate( {
			rules: {
				firstnamec: {
					min: {
						param: 5,
						depends: function( el ) {
							return ( /^a/ ).test( $( el ).val() );
						}
					}
				},
				lastname: {
					max: {
						param: 12
					},
					email: {
						depends: function() { return true; }
					}
				}
			}
		} ),
		rules = $( "#firstnamec" ).rules();

	equal( v.objectLength( rules ), 0 );

	$( "#firstnamec" ).val( "ab" );
	deepEqual( $( "#firstnamec" ).rules(), { min: 5 } );

	deepEqual( $( "#lastnamec" ).rules(), { max: 12, email: true } );
} );

test( "rules(), add and remove", function() {
	$.validator.addMethod( "customMethod1", function() {
		return false;
	}, "" );
	$( "#v2" ).validate();
	$( "#v2-i5" ).removeClass( "required" ).removeAttr( "minlength maxlength" );
	deepEqual( $( "#v2-i5" ).rules(), { customMethod1: "123" } );

	$( "#v2-i5" ).addClass( "required" ).attr( {
		minlength: 2,
		maxlength: 5
	} );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, minlength: 2, maxlength: 5, customMethod1: "123" } );

	$( "#v2-i5" ).addClass( "email" ).attr( { min: 5 } );
	deepEqual( $( "#v2-i5" ).rules(), { required: true, email: true, minlength: 2, maxlength: 5, min: 5, customMethod1: "123" } );

	$( "#v2-i5" ).removeClass( "required email" ).removeAttr( "minlength maxlength customMethod1 min" );
	deepEqual( $( "#v2-i5" ).rules(), {} );

	delete $.validator.methods.customMethod1;
	delete $.validator.messages.customMethod1;
} );

test( "rules(), add and remove static rules", function() {

	$( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: "required date"
		}
	} );

	deepEqual( $( "#firstnamec" ).rules(), { required: true, date: true } );

	$( "#firstnamec" ).rules( "remove", "date" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true } );
	$( "#firstnamec" ).rules( "add", "email" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true, email: true } );

	$( "#firstnamec" ).rules( "remove", "required" );
	deepEqual( $( "#firstnamec" ).rules(), { email: true } );

	deepEqual( $( "#firstnamec" ).rules( "remove" ), { email: true } );
	deepEqual( $( "#firstnamec" ).rules(), {} );

	$( "#firstnamec" ).rules( "add", "required email" );
	deepEqual( $( "#firstnamec" ).rules(), { required: true, email: true } );

	deepEqual( $( "#lastnamec" ).rules(), {} );
	$( "#lastnamec" ).rules( "add", "required" );
	$( "#lastnamec" ).rules( "add", {
		minlength: 2
	} );
	deepEqual( $( "#lastnamec" ).rules(), { required: true, minlength: 2 } );

	var removedRules = $( "#lastnamec" ).rules( "remove", "required email" );
	deepEqual( $( "#lastnamec" ).rules(), { minlength: 2 } );
	$( "#lastnamec" ).rules( "add", removedRules );
	deepEqual( $( "#lastnamec" ).rules(), { required: true, minlength: 2 } );
} );

test( "rules(), add messages", function() {
	$( "#firstnamec" ).attr( "title", null );
	var v = $( "#testForm1clean" ).validate( {
		rules: {
			firstnamec: "required"
		}
	} );
	$( "#testForm1clean" ).valid();
	$( "#firstnamec" ).valid();
	deepEqual( v.settings.messages.firstname, undefined );

	$( "#firstnamec" ).rules( "add", {
		messages: {
			required: "required"
		}
	} );

	$( "#firstnamec" ).valid();
	deepEqual( v.errorList[ 0 ] && v.errorList[ 0 ].message, "required" );

	$( "#firstnamec" ).val( "test" );
	$( "#firstnamec" ).valid();
	equal( v.errorList.length, 0 );
} );

test( "rules(), rangelength attribute as array", function() {
	$( "#testForm13" ).validate();
	deepEqual( $( "#cars-select" ).rules(), {
		required: true,
		rangelength: [ 2, 3 ]
	} );
} );

test( "rules(), normalizer", function() {
	var username = $( "#usernamec" ),
		urlc = $( "#urlc" ),
		lastname = $( "#lastnamec" ),
		v;

	username.val( "\t\t \r" );
	urlc.val( "" );

	v = $( "#testForm1clean" ).validate( {
		rules: {
			username: {
				required: true,

				// Using the normalizer to trim the value of the element
				// before validating it.
				normalizer: function( value ) {
					equal( this, username[ 0 ], "`this` in the normalizer should be the username element." );

					// Trim the value of the input
					return $.trim( value );
				}
			},
			urlc: {
				required: true,
				url: true,

				// Using the normalizer to append https:// if it's not
				// present on the input value
				normalizer: function( value ) {
					equal( this, urlc[ 0 ], "`this` in the normalizer should be the urlc element." );

					var url = value;

					// Check if it doesn't start with http:// or https:// or ftp://
					if ( url && url.substr( 0, 7 ) !== "http://" &&
						url.substr( 0, 8 ) !== "https://" &&
						url.substr( 0, 6 ) !== "ftp://" ) {

						// Then prefix with http:// or even https://
						url = "https://" + url;
					}

					// Return the new url
					return url;
				}
			},
			lastname: {
				required: true,

				// Using the normalizer to trim the value of the element
				// before validating it.
				normalizer: function( value ) {
					equal( this, lastname[ 0 ], "`this` in the normalizer should be the lastname element." );

					// Return null in order to make sure a exception is thrown
					// when normalizer returns a non string value.
					value = null;

					return value;
				}
			}
		}
	} );

	// Validate only the username and the url elements.
	username.valid();
	equal( v.invalidElements()[ 0 ], username[ 0 ], "The username should be invalid" );

	urlc.valid();
	equal( v.invalidElements()[ 0 ], urlc[ 0 ], "The url should be invalid" );

	equal( v.numberOfInvalids(), 2, "There is two invalid elements" );

	username.val( "something" );
	urlc.val( "google.com" );

	username.trigger( "keyup" );
	urlc.trigger( "keyup" );

	equal( v.numberOfInvalids(), 0, "All elements are valid" );
	equal( v.size(), 0, "All elements are valid" );

	// Validate the lastname element, which will throw an exception
	throws( function() {
		v.check( lastname[ 0 ] );
	}, function( err ) {
		return err.name === "TypeError" && err.message === "The normalizer should return a string value.";
	}, "This should throw a TypeError exception." );
} );

test( "rules() - on empty jquery set #1706", function() {
	var element = $( "#firstname .mynonexistantclass" );

	var result = element.rules( "add", "whatever" );
	strictEqual( result, undefined, "can work on an empty set without a js error" );
} );
<|endoftext|>


<commit_before>var should = require("should");
var rules = require("../chessjs/rules");
var _ = require("underscore");

var canMoveTo = function(piece, parsed) {
    var rightSquare = function(option) {
        return option.x === parsed.x && option.y === parsed.y;
    }

    var allMoves = parsed.mover.validMoves();
    var moves = allMoves.moves.filter(rightSquare);
    var caps = allMoves.captures.filter(rightSquare);

    return moves.length + caps.length === 1;
}

var hasMove = function(piece, move) {
    should.equal(canMoveTo(piece, move), true,
                 piece.type + " at (" + piece.x + ", " + piece.y + ") " +
                 "cannot move to (" + move.x + ", " + move.y + ")");
}

var noMoveTo = function(piece, move) {
    should.equal(canMoveTo(piece, move), false,
                 piece.type + " at (" + piece.x + ", " + piece.y + ") " +
                 "can move to (" + move.x + ", " + move.y + ")");
}

var checkMoves = function(moves, cont) {
    rules.withRules("base", function(Board, BaseRules) {
        var board = new Board();
        board.setup();
        _.each(moves, function(text, ix) {
            var parsed = board.parseMove(text);

            hasMove(parsed.mover, parsed);

            parsed.mover.moveTo(parsed.x, parsed.y, parsed.promo);
        });
        cont(board);
    });
}

var checkInvalid = function(moves, invalid, done) {
    checkMoves(moves, function(board) {
        var notAllowed = board.parseMove(invalid);

        noMoveTo(notAllowed.mover, notAllowed);

        done();
    });
}

describe('Basic rules', function() {
    it('should follow the right interface', function(done) {
        rules.withRules("base", function(Board, BaseRules) {
            should.exist(BaseRules.validMoves);
            should.exist(BaseRules.startingPieces);
            done();
        });
    });
});

describe('A pawn', function() {
    it('can move forward', function(done) {
        checkMoves(['a1-a2', 'a6-a5', 'b1-b3'], function() { done() });
    });
    it('can capture diagonally', function(done) {
        checkMoves(['a1-a3', 'b6-b4', 'a3-b4'], function() { done() });
    });
    it('can capture en passant', function(done) {
        checkMoves(['a1-a3', 'h6-h4', 'a3-a4', 'b6-b4', 'a4-b5'],
                   function() { done() });
    });
    it('cannot capture en passant after the initial move', function(done) {
        checkInvalid(['a1-a3', 'b6-b4', 'h1-h2', 'b4-b3'], 'a3-b4', done);
    });
});
<commit_msg>Add tests for all pieces.<commit_after>var should = require("should");
var rules = require("../chessjs/rules");
var _ = require("underscore");

var canMoveTo = function(piece, parsed) {
    var rightSquare = function(option) {
        return option.x === parsed.x && option.y === parsed.y;
    }

    var allMoves = parsed.mover.validMoves();
    var moves = allMoves.moves.filter(rightSquare);
    var caps = allMoves.captures.filter(rightSquare);

    return moves.length + caps.length === 1;
}

var hasMove = function(piece, move) {
    should.equal(canMoveTo(piece, move), true,
                 piece.type + " at (" + piece.x + ", " + piece.y + ") " +
                 "cannot move to (" + move.x + ", " + move.y + ")");
}

var noMoveTo = function(piece, move) {
    should.equal(canMoveTo(piece, move), false,
                 piece.type + " at (" + piece.x + ", " + piece.y + ") " +
                 "can move to (" + move.x + ", " + move.y + ")");
}

var checkMoves = function(moves, cont) {
    rules.withRules("base", function(Board, BaseRules) {
        var board = new Board();
        board.setup();
        _.each(moves, function(text, ix) {
            var parsed = board.parseMove(text);

            hasMove(parsed.mover, parsed);

            parsed.mover.moveTo(parsed.x, parsed.y, parsed.promo);
        });
        cont(board);
    });
}

var checkInvalid = function(moves, invalid, done) {
    checkMoves(moves, function(board) {
        var notAllowed = board.parseMove(invalid);

        noMoveTo(notAllowed.mover, notAllowed);

        done();
    });
}

describe('Basic rules', function() {
    it('should follow the right interface', function(done) {
        rules.withRules("base", function(Board, BaseRules) {
            should.exist(BaseRules.validMoves);
            should.exist(BaseRules.startingPieces);
            done();
        });
    });
});

describe('A king', function() {
    it('moves only to adjacent squares', function(done) {
        checkMoves(['d1-d3', 'a6-a5', 'd0-d1', 'a5-a4', 'd1-c2'],
                   function() { done() });
    });
});

describe('A queen', function() {
    it('can move like a rook', function(done) {
        checkMoves(['e1-e3', 'a6-a5', 'e0-e2', 'a5-a4', 'e2-a2'],
                   function() { done() });
    });
    it('can move like a bishop', function(done) {
        checkMoves(['d1-d3', 'a6-a5', 'e0-a4'],
                   function() { done() });
    });
});

describe('A rook', function() {
    it('can move on columns and rows', function(done) {
        checkMoves(['a1-a3', 'a6-a5', 'a0-a2', 'h6-h5', 'a2-h2'],
                   function() { done() });
    });
});

describe('A bishop', function() {
    it('can move on diagonals', function(done) {
        checkMoves(['d1-d3', 'a6-a5', 'c0-f3', 'a5-a4', 'f3-c6'],
                   function() { done() });
    });
});

describe('A knight', function() {
    it('moves in L shapes', function(done) {
        checkMoves(['b0-a2', 'a6-a5', 'a2-c3', 'a5-a4', 'c3-e2'],
                   function() { done() });
    });
});

describe('A pawn', function() {
    it('can move forward', function(done) {
        checkMoves(['a1-a2', 'a6-a5', 'b1-b3'], function() { done() });
    });
    it('can capture diagonally', function(done) {
        checkMoves(['a1-a3', 'b6-b4', 'a3-b4'], function() { done() });
    });
    it('can capture en passant', function(done) {
        checkMoves(['a1-a3', 'h6-h4', 'a3-a4', 'b6-b4', 'a4-b5'],
                   function() { done() });
    });
    it('cannot capture en passant after the initial move', function(done) {
        checkInvalid(['a1-a3', 'b6-b4', 'h1-h2', 'b4-b3'], 'a3-b4', done);
    });
});
<|endoftext|>


<commit_before>// Load in dependencies
var expect = require('chai').expect;
var scriptUtils = require('./utils/script');

// Run our tests
// DEV: `scopeInfo` is distributed across `with.js` (`insideWith`),
//   `top-level.js` (`topLevel`), `declared.js` (`declared`),
//   `lexical.js`/`block.js` (`type` except for `undeclared`)
describe('ecma-variable-scope', function () {
  describe.only('marking up an AST for its scopes', function () {
    scriptUtils.interpretFnAst(function () {
      function hello(world) {
        var hai = true;
      }
    });
    before(function grabScope () {
      // {Program} (ast) -> {function} (body[0]) -> {var} (body.body[0])
      //  -> hai (declarations[0].id)
      this.identifier = this.ast.body[0].body.body[0].declarations[0].id;
      this.scope = this.identifier.scope;
    });
    after(function cleanup () {
      delete this.identifier;
      delete this.scope;
    });

    it('gives a `scope` a `type`', function () {
      expect(this.scope).to.have.property('type', 'lexical');
    });

    it.skip('gives a `scope` a `node`', function () {
      // {Program} (ast) -> {logger.info} (body[1]) -> logger (expression.callee.object)
      var identifier = this.ast.body[1].expression.callee.object;
      expect(identifier).to.have.property('scope');
      expect(identifier).to.have.property('scopeInfo');
    });

    it.skip('gives a `scope` a `parent`', function () {
      // {Program} (ast) -> {logger.info} (body[1]) -> logger (expression.callee.object)
      var identifier = this.ast.body[1].expression.callee.object;
      expect(identifier).to.have.property('scope');
      expect(identifier).to.have.property('scopeInfo');
    });

    it.skip('saves its identifiers', function () {

    });

    it.skip('saves its child scopes', function () {

    });
  });

  // TODO: Test out `undefined` parent

  // TODO: scopeInfo.type = `undeclared` and `scope` === undefined
});
<commit_msg>Added test for node but need parent support<commit_after>// Load in dependencies
var expect = require('chai').expect;
var scriptUtils = require('./utils/script');

// Run our tests
// DEV: `scopeInfo` is distributed across `with.js` (`insideWith`),
//   `top-level.js` (`topLevel`), `declared.js` (`declared`),
//   `lexical.js`/`block.js` (`type` except for `undeclared`)
describe('ecma-variable-scope', function () {
  describe.only('marking up an AST for its scopes', function () {
    scriptUtils.interpretFnAst(function () {
      function hello() {
        function world() {
          var hai = true;
        }
      }
    });
    before(function grabScope () {
      // {Program} (ast) -> {function} (body[0]) -> {var} (body.body[0])
      //  -> hai (declarations[0].id)
      this.fn1 = this.ast.body[0];
      this.identifier = this.fn.body.body[0].declarations[0].id;
      this.scope = this.identifier.scope;
    });
    after(function cleanup () {
      delete this.fn;
      delete this.identifier;
      delete this.scope;
    });

    it('gives a `scope` a `type`', function () {
      expect(this.scope).to.have.property('type', 'lexical');
    });

    it('gives a `scope` a `node`', function () {
      expect(this.scope).to.have.property('node', this.fn);
    });

    it('gives a `scope` a `parent`', function () {
      expect(this.scope).to.have.property('scope');
      expect(identifier).to.have.property('scopeInfo');
    });

    it.skip('saves its identifiers', function () {

    });

    it.skip('saves its child scopes', function () {

    });
  });

  // TODO: Test out `undefined` parent

  // TODO: scopeInfo.type = `undeclared` and `scope` === undefined
});
<|endoftext|>


<commit_before>/* jshint expr: true */
/* global before, beforeEach, after */

var _ = require('lodash');
var q = require('q');
var avn = require('..');
var path = require('path');
var chalk = require('chalk');
var setup = require('../lib/setup');
var child_process = require('child_process');
var temp = require('temp').track();
var fs = require('fs');
var fsq = {
  mkdir: q.denodeify(fs.mkdir)
};

var chai = require('chai');
var expect = chai.expect;
chai.use(require('sinon-chai'));

var capture = require('./helpers').capture;
var fillTemporaryHome = function(temporaryHome, source) {
  var deferred = q.defer();
  var fullSource = path.resolve(path.join(__dirname, 'examples', source)) + '/';
  var cmd = child_process.spawn('/bin/cp', ['-RL', fullSource, temporaryHome]);
  cmd.stdout.pipe(process.stdout);
  cmd.stderr.pipe(process.stderr);
  cmd.on('close', function(code) {
    if (code === 0) { deferred.resolve(); }
    else { deferred.reject(new Error('cp exited with status: ' + code)); }
  });
  return deferred.promise;
};

describe('avn setup', function() {
  var temporaryHome;
  var home = process.env.HOME;
  var nodePath = process.env.NODE_PATH;
  var chalkEnabled = chalk.enabled;

  before(function() {
    chalk.enabled = false;
  });

  after(function() {
    chalk.enabled = chalkEnabled;
  });

  beforeEach(function() {
    temporaryHome = temp.mkdirSync();
    process.env.HOME = temporaryHome;
    process.env.NODE_PATH = path.resolve(path.join(__dirname, 'examples/node_install/node_modules'));
    require('module')._initPaths();
  });

  afterEach(function() {
    process.env.HOME = home;
    process.env.NODE_PATH = nodePath;
    require('module')._initPaths();
    temp.cleanup();
  });

  it('creates .bash_profile', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._updateProfile(); }).fin(std.restore).done(function() {
      expect(fs.existsSync(path.join(temporaryHome, '.bash_profile'))).to.be.true;
      expect(std.out).to.eql(
        'avn: profile setup complete (~/.bash_profile)\n' +
        'avn: restart your terminal to start using avn\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  // TODO: make this work on Travis
  it.skip('appends to .bash_profile', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .fin(std.restore)
    .done(function() {
      var file = path.join(temporaryHome, '.bash_profile');
      var contents = fs.readFileSync(file, 'utf8');
      expect(contents).to.contain('avn');
      expect(contents).to.contain('alias grep');
      expect(std.out).to.eql(
        'avn: profile setup complete (~/.bash_profile)\n' +
        'avn: restart your terminal to start using avn\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  // TODO: make this work on Travis
  it.skip('leaves .bash_profile untouched', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_avn_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .fin(std.restore)
    .done(function() {
      var file = path.join(temporaryHome, '.bash_profile');
      var contents = fs.readFileSync(file, 'utf8');
      expect(contents).to.contain('avn');
      expect(contents.split().length).to.eql(1);
      expect(std.out).to.eql(
        'avn: profile already set up (~/.bash_profile)\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  it('errors if .bash_profile cannot be written', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_protected_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .catch(function(e) {
      expect(std.out).to.eql('');
      expect(std.err).to.eql('');
      expect(e.code).to.eql('EACCES');
    })
    .fin(std.restore)
    .done(function() { done(); });
  });

  it.skip('installs to ~/.avn', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avn install', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avn_outdated')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avn install', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avn_futuristic')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('creates ~/.avnrc', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avnrc', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avnrc_missing_plugins')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('leaves ~/.avnrc untouched', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avnrc_plugins_current')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('runs all actions together', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });
});
<commit_msg>Fixing tests on Travis.<commit_after>/* jshint expr: true */
/* global before, beforeEach, after */

var _ = require('lodash');
var q = require('q');
var avn = require('..');
var path = require('path');
var chalk = require('chalk');
var setup = require('../lib/setup');
var child_process = require('child_process');
var temp = require('temp').track();
var fs = require('fs');
var fsq = {
  mkdir: q.denodeify(fs.mkdir)
};

var chai = require('chai');
var expect = chai.expect;
chai.use(require('sinon-chai'));

var capture = require('./helpers').capture;
var fillTemporaryHome = function(temporaryHome, source) {
  var deferred = q.defer();
  var fullSource = path.resolve(path.join(__dirname, 'examples', source)) + '/.';
  var cmd = child_process.spawn('/bin/cp', ['-RL', fullSource, temporaryHome]);
  cmd.stdout.pipe(process.stdout);
  cmd.stderr.pipe(process.stderr);
  cmd.on('close', function(code) {
    if (code === 0) { deferred.resolve(); }
    else { deferred.reject(new Error('cp exited with status: ' + code)); }
  });
  return deferred.promise;
};

describe('avn setup', function() {
  var temporaryHome;
  var home = process.env.HOME;
  var nodePath = process.env.NODE_PATH;
  var chalkEnabled = chalk.enabled;

  before(function() {
    chalk.enabled = false;
  });

  after(function() {
    chalk.enabled = chalkEnabled;
  });

  beforeEach(function() {
    temporaryHome = temp.mkdirSync();
    process.env.HOME = temporaryHome;
    process.env.NODE_PATH = path.resolve(path.join(__dirname, 'examples/node_install/node_modules'));
    require('module')._initPaths();
  });

  afterEach(function() {
    process.env.HOME = home;
    process.env.NODE_PATH = nodePath;
    require('module')._initPaths();
    temp.cleanup();
  });

  it('creates .bash_profile', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._updateProfile(); }).fin(std.restore).done(function() {
      expect(fs.existsSync(path.join(temporaryHome, '.bash_profile'))).to.be.true;
      expect(std.out).to.eql(
        'avn: profile setup complete (~/.bash_profile)\n' +
        'avn: restart your terminal to start using avn\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  it('appends to .bash_profile', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .fin(std.restore)
    .done(function() {
      var file = path.join(temporaryHome, '.bash_profile');
      var contents = fs.readFileSync(file, 'utf8');
      expect(contents).to.contain('avn');
      expect(contents).to.contain('alias grep');
      expect(std.out).to.eql(
        'avn: profile setup complete (~/.bash_profile)\n' +
        'avn: restart your terminal to start using avn\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  it('leaves .bash_profile untouched', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_avn_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .fin(std.restore)
    .done(function() {
      var file = path.join(temporaryHome, '.bash_profile');
      var contents = fs.readFileSync(file, 'utf8');
      expect(contents).to.contain('avn');
      expect(contents.split().length).to.eql(1);
      expect(std.out).to.eql(
        'avn: profile already set up (~/.bash_profile)\n');
      expect(std.err).to.eql('');
      done();
    });
  });

  it('errors if .bash_profile cannot be written', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_with_protected_bash_profile')
    .then(function() { return setup._updateProfile(); })
    .catch(function(e) {
      expect(std.out).to.eql('');
      expect(std.err).to.eql('');
      expect(e.code).to.eql('EACCES');
    })
    .fin(std.restore)
    .done(function() { done(); });
  });

  it.skip('installs to ~/.avn', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avn install', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avn_outdated')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avn install', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avn_futuristic')
    .then(function() { return setup._install(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('creates ~/.avnrc', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('updates ~/.avnrc', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avnrc_missing_plugins')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('leaves ~/.avnrc untouched', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_avnrc_plugins_current')
    .then(function() { return setup._updateConfigurationFile(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });

  it.skip('runs all actions together', function(done) {
    var std = capture(['out', 'err']);
    fillTemporaryHome(temporaryHome, 'home_empty')
    .then(function() { return setup(); }).fin(std.restore).done(function() {
      // make assertions
      done();
    });
  });
});
<|endoftext|>


<commit_before>// This file manages all async state transitions.
//
// These attach to actions to help state changes along.
//
// For example, `TaskActions.load` everntually yields either
// `TaskActions.loaded` or `TaskActions.FAILED`
import adapters from './adapter';
import { pick } from 'lodash';
import { CoursePracticeActions } from '../flux/practice';
import { CourseGuideActions } from '../flux/guide';
import * as PerformanceForecast from '../flux/performance-forecast';

import { TaskActions } from '../flux/task';
import { TaskStepActions, TaskStepStore } from '../flux/task-step';
import { TaskPlanActions, TaskPlanStore } from '../flux/task-plan';
import { CCDashboardActions } from '../flux/cc-dashboard';
import Exercises from '../models/exercises';
import ReferenceBook from '../models/reference-book';
import ReferenceBookPage from '../models/reference-book/page';
import Ecosystems from '../models/ecosystems';
import { ReferenceBookExerciseActions } from '../flux/reference-book-exercise';

import TaskPlanHelpers from '../helpers/task-plan';
import { FeatureFlagsApi as FeatureFlags } from '../models/feature_flags';
import Survey from '../models/research-surveys/survey';
import Job from '../models/job';
import User from '../models/user';
import { UserTerms } from '../models/user/terms';
import Course from '../models/course';
import Period from '../models/course/period';
import Courses from '../models/courses-map';
import Offerings from '../models/course/offerings';
import CourseCreate from '../models/course/create';
import TeacherTaskPlans from '../models/course/task-plans';
import PastTaskPlans from '../models/course/past-task-plans';
import Student from '../models/course/student';
import CourseEnroll from '../models/course/enroll';
import Payments from '../models/payments';
import Purchases from '../models/purchases';
import Purchase from '../models/purchases/purchase';
import { CourseStudentTasks } from '../models/student-tasks';
import StudentTask from '../models/student/task';
import CourseRoster from '../models/course/roster';
import CourseLMS from '../models/course/lms';
import CoursePairLMS from '../models/course/pair-to-lms';
import CourseScores from '../models/course/scores';
import ScoresExport from '../models/jobs/scores-export';
import LmsPushScores from '../models/jobs/lms-score-push';
import TaskResult from '../models/course/scores/task-result';
import CourseTeacher from '../models/course/teacher';
import TeacherTaskPlan from '../models/task-plan/teacher';
import TaskPlanStats from '../models/task-plan/stats';
import { ResponseValidation } from '../models/response_validation';
import { PageNotes, Note } from '../models/notes';

const { connectModify, connectCreate, connectRead, connectUpdate, connectDelete, connectModelCreate, connectModelRead, connectModelUpdate, connectModelDelete } = adapters;

const startAPI = function() {
  connectRead(TaskActions, { pattern: 'tasks/{id}' });
  connectDelete(TaskActions, { pattern: 'tasks/{id}' });

  connectRead(TaskPlanActions, { pattern: 'plans/{id}' });
  connectDelete(TaskPlanActions, { pattern: 'plans/{id}' });

  connectUpdate(TaskPlanActions, { data: TaskPlanStore.getChanged }, TaskPlanHelpers.apiEndpointOptions);

  connectUpdate(
    TaskPlanActions,
    {
      trigger: 'saveSilent',

      handleError(...args) {
        TaskPlanActions.erroredSilent(...Array.from(args || []));
        return true;
      },

      data: TaskPlanStore.getChanged,
    },
    TaskPlanHelpers.apiEndpointOptions,
  );

  connectRead(CourseGuideActions, { pattern: 'courses/{id}/guide' });

  connectRead(CCDashboardActions, { pattern: 'courses/{id}/cc/dashboard' });
  connectRead(CoursePracticeActions, { pattern: 'courses/{id}/practice' });

  connectCreate(
    CoursePracticeActions,
    {
      url({ courseId, query }) {
        const url = `courses/${courseId}/practice`;
        if ((query != null ? query.worst : undefined)) { return `${url}/worst`; } else { return url; }
      },

      data({ query }) { return query; },
    },
  );

  connectRead(PerformanceForecast.Student.actions, { pattern: 'courses/{id}/guide' });
  connectRead(PerformanceForecast.Teacher.actions, { pattern: 'courses/{id}/teacher_guide' });
  connectRead(PerformanceForecast.TeacherStudent.actions, function(id, { roleId }) {
    const url = `courses/${id}/guide/role/${roleId}`;
    const data = { id, roleId };
    return { url, data };
  });

  //  connectRead(EcosystemsActions, url: 'ecosystems')

  connectRead(TaskStepActions, { pattern: 'steps/{id}' });
  connectRead(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'loadPersonalized' },
    {
      handleError(...args) {
        TaskStepActions.loadedNoPersonalized(...Array.from(args || []));
        return true;
      },
    },
  );
  connectModify(
    TaskActions,
    { pattern: 'steps/{id}/completed', trigger: 'completeStep', onSuccess: 'stepCompleted' },
    {
      data(id) {
        const step = TaskStepStore.get(id);
        return pick(step, 'free_response', 'answer_id', 'garbage_estimate');
      },
    },
  );

  connectUpdate(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'saveFreeResponseAnswer' },
    {
      data(id) {
        const step = TaskStepStore.get(id);
        return pick(step, 'free_response', 'garbage_estimate');
      },
    },
  );
  connectUpdate(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'setAnswerId' },
    {
      data(id, answerId) {
        return { answer_id: answerId };
      },
    },
  );

  connectRead(ReferenceBookExerciseActions, { url(url) { return url; } });

  connectModelRead(Exercises.constructor, 'fetch', { onSuccess: 'onLoaded' });

  connectModelRead(Ecosystems.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'ecosystems' });

  connectModelRead(ReferenceBook, 'fetch', { pattern: 'ecosystems/{id}/readings', onSuccess: 'onApiRequestComplete' });
  connectModelRead(ReferenceBookPage, 'fetchContent', {
    pattern: 'ecosystems/{ecosystemId}/pages/{cnx_id}',
    onSuccess: 'onContentFetchComplete',
    onFail: 'onContentFetchFail',
  });

  // "User" is actually an instance, but connectModel works at the class level
  connectModelUpdate(User.constructor, 'saveTourView',
    { pattern: 'user/tours/{id}' }
  );

  connectModelUpdate(Note, 'save', {
    onSuccess: 'onUpdated',
    method() { return this.isNew ? 'POST' : 'PATCH'; },
    pattern() { return 'courses/{courseId}/notes/{chapterSection}' + (this.isNew ? '' : '/{id}'); },
  });
  connectModelDelete(Note, 'destroy', {
    onSuccess: 'onDeleted',
    pattern: 'courses/{courseId}/notes/{chapterSection}/{id}',
  });
  connectModelRead(PageNotes, 'fetch', {
    onSuccess: 'onLoaded',
    pattern: 'courses/{courseId}/notes/{chapterSection}',
  });

  connectModelRead(Course, 'fetch', { pattern: 'courses/{id}' });

  connectModelRead(UserTerms, 'fetch', { onSuccess: 'onLoaded', url: 'terms' });
  connectModelUpdate(UserTerms, 'sign', { onSuccess: 'onSigned', pattern: 'terms/{ids}', method: 'PUT' });
  connectModelUpdate(Survey, 'save',
    { pattern: 'research_surveys/{id}' }
  );
  connectModelRead(Purchases.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'purchases' });
  connectModelUpdate(
    Purchase,
    'refund',
    {
      onSuccess: 'onRefunded',
      pattern: 'purchases/{item_uuid}/refund',
      method: 'PUT',
      data() { return { survey: this.refund_survey }; },
    },
  );
  connectModelCreate(
    User.constructor,
    'logEvent',
    {
      method: 'POST',
      pattern: 'log/event/{category}/{code}',
      data({ data }) { return { data }; },
    },
  );
  connectModelRead(Offerings.constructor, 'fetch', { url: 'offerings', onSuccess: 'onLoaded' });

  connectModelCreate(CourseCreate, 'save', { onSuccess: 'onCreated' });

  connectModelRead(
    TeacherTaskPlans,
    'fetch',
    {
      pattern: 'courses/{course.id}/dashboard',
      onSuccess: 'onLoaded',

      params({ startAt, endAt }) {
        return {
          start_at: startAt,
          end_at: endAt,
        };
      },
    },
  );

  connectModelRead(
    PastTaskPlans,
    'fetch',
    {
      pattern: 'courses/{course.id}/plans',
      onSuccess: 'onLoaded',

      params: {
        clone_status: 'unused_source',
      },
    },
  );

  connectModelRead(ResponseValidation, 'validate', { pattern: 'validate', onSuccess: 'onValidationComplete' });

  connectModelUpdate(Student, 'saveOwnStudentId', { pattern: 'user/courses/{course.id}/student', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Student, 'saveStudentId', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Student, 'savePeriod', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelDelete(Student, 'drop', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' } );
  connectModelUpdate(Student, 'unDrop', { pattern: 'students/{id}/undrop', method: 'PUT', onSuccess: 'onApiRequestComplete' } );

  connectModelCreate(CourseEnroll, 'create', { url: 'enrollment', onSuccess: 'onEnrollmentCreate', onFail: 'setApiErrors' });
  connectModelUpdate(
    CourseEnroll,
    'confirm',
    {
      pattern: 'enrollment/{id}/approve',
      method: 'PUT',
      onSuccess: 'onApiRequestComplete',
      onFail: 'setApiErrors',
    },
  );

  connectModelRead(CourseStudentTasks, 'fetch', { onSuccess: 'onLoaded', pattern: 'courses/{course.id}/dashboard' });
  connectModelDelete(StudentTask, 'hide', { onSuccess: 'onHidden', pattern: 'tasks/{id}' });

  connectModelUpdate(Course, 'save', { pattern: 'courses/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Course,
    'saveExerciseExclusion', { pattern: 'courses/{id}/exercises', onSuccess: 'onExerciseExcluded' }
  );

  connectModelRead(CourseLMS, 'fetch', { pattern: 'lms/courses/{course.id}', onSuccess: 'onApiRequestComplete' });

  connectModelUpdate(CoursePairLMS, 'save', { method: 'POST', pattern: 'lms/courses/{course.id}/pair', onSuccess: 'onPaired' });

  connectModelUpdate(LmsPushScores, 'start', { method: 'PUT', pattern: 'lms/courses/{course.id}/push_scores', onSuccess: 'onStarted' });

  connectModelRead(CourseRoster, 'fetch', { pattern: 'courses/{courseId}/roster', onSuccess: 'onApiRequestComplete' });

  connectModelDelete(CourseTeacher, 'drop', { pattern: 'teachers/{id}', onSuccess: 'onDropped' });

  connectModelCreate(Period, 'create', { pattern: 'courses/{courseId}/periods', onSuccess: 'afterCreate' });
  connectModelUpdate(Period, 'save', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelDelete(Period, 'archive', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Period, 'unarchive', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });

  connectModelRead(CourseScores, 'fetch',
    { pattern: 'courses/{courseId}/performance', onSuccess: 'onFetchComplete' });

  connectModelUpdate(TaskResult, 'acceptLate', { method: 'PUT', pattern: 'tasks/{id}/accept_late_work', onSuccess: 'onLateWorkAccepted' });

  connectModelUpdate(TaskResult, 'rejectLate', { method: 'PUT', pattern: 'tasks/{id}/reject_late_work', onSuccess: 'onLateWorkRejected' });

  connectModelRead(Job, 'requestJobStatus', { onSuccess: 'onJobUpdate', onFail: 'onJobUpdateFailure', pattern: 'jobs/{jobId}' });

  connectModelCreate(ScoresExport, 'create', { onSuccess: 'onCreated', pattern: 'courses/{course.id}/performance/export' });

  connectModelRead(TeacherTaskPlan, 'fetch', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}' });
  connectModelRead(TaskPlanStats, 'fetch', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}/stats' });

  connectModelRead(TaskPlanStats, 'fetchReview', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}/review' });

  return connectModelRead(Courses.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'user/courses' });
};

const BOOTSTRAPED_MODELS = {
  user:     User,
  courses:  Courses,
  payments: Payments,
  feature_flags: FeatureFlags,
};

const bootstrap = function(bootstrapData) {
  window._MODELS.bootstrapData = bootstrapData;
  for (let storeId in BOOTSTRAPED_MODELS) {
    const model = BOOTSTRAPED_MODELS[storeId];
    const data = bootstrapData[storeId];
    if (data) { model.bootstrap(data); }
  }
  return startAPI();
};

const start = function(bootstrapData) {
  return bootstrapData ? bootstrap(bootstrapData) : {};
};

export { startAPI, start };
<commit_msg>remove ResponseValidation from api/index<commit_after>// This file manages all async state transitions.
//
// These attach to actions to help state changes along.
//
// For example, `TaskActions.load` everntually yields either
// `TaskActions.loaded` or `TaskActions.FAILED`
import adapters from './adapter';
import { pick } from 'lodash';
import { CoursePracticeActions } from '../flux/practice';
import { CourseGuideActions } from '../flux/guide';
import * as PerformanceForecast from '../flux/performance-forecast';

import { TaskActions } from '../flux/task';
import { TaskStepActions, TaskStepStore } from '../flux/task-step';
import { TaskPlanActions, TaskPlanStore } from '../flux/task-plan';
import { CCDashboardActions } from '../flux/cc-dashboard';
import Exercises from '../models/exercises';
import ReferenceBook from '../models/reference-book';
import ReferenceBookPage from '../models/reference-book/page';
import Ecosystems from '../models/ecosystems';
import { ReferenceBookExerciseActions } from '../flux/reference-book-exercise';

import TaskPlanHelpers from '../helpers/task-plan';
import { FeatureFlagsApi as FeatureFlags } from '../models/feature_flags';
import Survey from '../models/research-surveys/survey';
import Job from '../models/job';
import User from '../models/user';
import { UserTerms } from '../models/user/terms';
import Course from '../models/course';
import Period from '../models/course/period';
import Courses from '../models/courses-map';
import Offerings from '../models/course/offerings';
import CourseCreate from '../models/course/create';
import TeacherTaskPlans from '../models/course/task-plans';
import PastTaskPlans from '../models/course/past-task-plans';
import Student from '../models/course/student';
import CourseEnroll from '../models/course/enroll';
import Payments from '../models/payments';
import Purchases from '../models/purchases';
import Purchase from '../models/purchases/purchase';
import { CourseStudentTasks } from '../models/student-tasks';
import StudentTask from '../models/student/task';
import CourseRoster from '../models/course/roster';
import CourseLMS from '../models/course/lms';
import CoursePairLMS from '../models/course/pair-to-lms';
import CourseScores from '../models/course/scores';
import ScoresExport from '../models/jobs/scores-export';
import LmsPushScores from '../models/jobs/lms-score-push';
import TaskResult from '../models/course/scores/task-result';
import CourseTeacher from '../models/course/teacher';
import TeacherTaskPlan from '../models/task-plan/teacher';
import TaskPlanStats from '../models/task-plan/stats';
import { ResponseValidation } from '../models/response_validation';
import { PageNotes, Note } from '../models/notes';

const { connectModify, connectCreate, connectRead, connectUpdate, connectDelete, connectModelCreate, connectModelRead, connectModelUpdate, connectModelDelete } = adapters;

const startAPI = function() {
  connectRead(TaskActions, { pattern: 'tasks/{id}' });
  connectDelete(TaskActions, { pattern: 'tasks/{id}' });

  connectRead(TaskPlanActions, { pattern: 'plans/{id}' });
  connectDelete(TaskPlanActions, { pattern: 'plans/{id}' });

  connectUpdate(TaskPlanActions, { data: TaskPlanStore.getChanged }, TaskPlanHelpers.apiEndpointOptions);

  connectUpdate(
    TaskPlanActions,
    {
      trigger: 'saveSilent',

      handleError(...args) {
        TaskPlanActions.erroredSilent(...Array.from(args || []));
        return true;
      },

      data: TaskPlanStore.getChanged,
    },
    TaskPlanHelpers.apiEndpointOptions,
  );

  connectRead(CourseGuideActions, { pattern: 'courses/{id}/guide' });

  connectRead(CCDashboardActions, { pattern: 'courses/{id}/cc/dashboard' });
  connectRead(CoursePracticeActions, { pattern: 'courses/{id}/practice' });

  connectCreate(
    CoursePracticeActions,
    {
      url({ courseId, query }) {
        const url = `courses/${courseId}/practice`;
        if ((query != null ? query.worst : undefined)) { return `${url}/worst`; } else { return url; }
      },

      data({ query }) { return query; },
    },
  );

  connectRead(PerformanceForecast.Student.actions, { pattern: 'courses/{id}/guide' });
  connectRead(PerformanceForecast.Teacher.actions, { pattern: 'courses/{id}/teacher_guide' });
  connectRead(PerformanceForecast.TeacherStudent.actions, function(id, { roleId }) {
    const url = `courses/${id}/guide/role/${roleId}`;
    const data = { id, roleId };
    return { url, data };
  });

  //  connectRead(EcosystemsActions, url: 'ecosystems')

  connectRead(TaskStepActions, { pattern: 'steps/{id}' });
  connectRead(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'loadPersonalized' },
    {
      handleError(...args) {
        TaskStepActions.loadedNoPersonalized(...Array.from(args || []));
        return true;
      },
    },
  );
  connectModify(
    TaskActions,
    { pattern: 'steps/{id}/completed', trigger: 'completeStep', onSuccess: 'stepCompleted' },
    {
      data(id) {
        const step = TaskStepStore.get(id);
        return pick(step, 'free_response', 'answer_id', 'garbage_estimate');
      },
    },
  );

  connectUpdate(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'saveFreeResponseAnswer' },
    {
      data(id) {
        const step = TaskStepStore.get(id);
        return pick(step, 'free_response', 'garbage_estimate');
      },
    },
  );
  connectUpdate(
    TaskStepActions,
    { pattern: 'steps/{id}', trigger: 'setAnswerId' },
    {
      data(id, answerId) {
        return { answer_id: answerId };
      },
    },
  );

  connectRead(ReferenceBookExerciseActions, { url(url) { return url; } });

  connectModelRead(Exercises.constructor, 'fetch', { onSuccess: 'onLoaded' });

  connectModelRead(Ecosystems.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'ecosystems' });

  connectModelRead(ReferenceBook, 'fetch', { pattern: 'ecosystems/{id}/readings', onSuccess: 'onApiRequestComplete' });
  connectModelRead(ReferenceBookPage, 'fetchContent', {
    pattern: 'ecosystems/{ecosystemId}/pages/{cnx_id}',
    onSuccess: 'onContentFetchComplete',
    onFail: 'onContentFetchFail',
  });

  // "User" is actually an instance, but connectModel works at the class level
  connectModelUpdate(User.constructor, 'saveTourView',
    { pattern: 'user/tours/{id}' }
  );

  connectModelUpdate(Note, 'save', {
    onSuccess: 'onUpdated',
    method() { return this.isNew ? 'POST' : 'PATCH'; },
    pattern() { return 'courses/{courseId}/notes/{chapterSection}' + (this.isNew ? '' : '/{id}'); },
  });
  connectModelDelete(Note, 'destroy', {
    onSuccess: 'onDeleted',
    pattern: 'courses/{courseId}/notes/{chapterSection}/{id}',
  });
  connectModelRead(PageNotes, 'fetch', {
    onSuccess: 'onLoaded',
    pattern: 'courses/{courseId}/notes/{chapterSection}',
  });

  connectModelRead(Course, 'fetch', { pattern: 'courses/{id}' });

  connectModelRead(UserTerms, 'fetch', { onSuccess: 'onLoaded', url: 'terms' });
  connectModelUpdate(UserTerms, 'sign', { onSuccess: 'onSigned', pattern: 'terms/{ids}', method: 'PUT' });
  connectModelUpdate(Survey, 'save',
    { pattern: 'research_surveys/{id}' }
  );
  connectModelRead(Purchases.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'purchases' });
  connectModelUpdate(
    Purchase,
    'refund',
    {
      onSuccess: 'onRefunded',
      pattern: 'purchases/{item_uuid}/refund',
      method: 'PUT',
      data() { return { survey: this.refund_survey }; },
    },
  );
  connectModelCreate(
    User.constructor,
    'logEvent',
    {
      method: 'POST',
      pattern: 'log/event/{category}/{code}',
      data({ data }) { return { data }; },
    },
  );
  connectModelRead(Offerings.constructor, 'fetch', { url: 'offerings', onSuccess: 'onLoaded' });

  connectModelCreate(CourseCreate, 'save', { onSuccess: 'onCreated' });

  connectModelRead(
    TeacherTaskPlans,
    'fetch',
    {
      pattern: 'courses/{course.id}/dashboard',
      onSuccess: 'onLoaded',

      params({ startAt, endAt }) {
        return {
          start_at: startAt,
          end_at: endAt,
        };
      },
    },
  );

  connectModelRead(
    PastTaskPlans,
    'fetch',
    {
      pattern: 'courses/{course.id}/plans',
      onSuccess: 'onLoaded',

      params: {
        clone_status: 'unused_source',
      },
    },
  );

  connectModelUpdate(Student, 'saveOwnStudentId', { pattern: 'user/courses/{course.id}/student', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Student, 'saveStudentId', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Student, 'savePeriod', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelDelete(Student, 'drop', { pattern: 'students/{id}', onSuccess: 'onApiRequestComplete' } );
  connectModelUpdate(Student, 'unDrop', { pattern: 'students/{id}/undrop', method: 'PUT', onSuccess: 'onApiRequestComplete' } );

  connectModelCreate(CourseEnroll, 'create', { url: 'enrollment', onSuccess: 'onEnrollmentCreate', onFail: 'setApiErrors' });
  connectModelUpdate(
    CourseEnroll,
    'confirm',
    {
      pattern: 'enrollment/{id}/approve',
      method: 'PUT',
      onSuccess: 'onApiRequestComplete',
      onFail: 'setApiErrors',
    },
  );

  connectModelRead(CourseStudentTasks, 'fetch', { onSuccess: 'onLoaded', pattern: 'courses/{course.id}/dashboard' });
  connectModelDelete(StudentTask, 'hide', { onSuccess: 'onHidden', pattern: 'tasks/{id}' });

  connectModelUpdate(Course, 'save', { pattern: 'courses/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Course,
    'saveExerciseExclusion', { pattern: 'courses/{id}/exercises', onSuccess: 'onExerciseExcluded' }
  );

  connectModelRead(CourseLMS, 'fetch', { pattern: 'lms/courses/{course.id}', onSuccess: 'onApiRequestComplete' });

  connectModelUpdate(CoursePairLMS, 'save', { method: 'POST', pattern: 'lms/courses/{course.id}/pair', onSuccess: 'onPaired' });

  connectModelUpdate(LmsPushScores, 'start', { method: 'PUT', pattern: 'lms/courses/{course.id}/push_scores', onSuccess: 'onStarted' });

  connectModelRead(CourseRoster, 'fetch', { pattern: 'courses/{courseId}/roster', onSuccess: 'onApiRequestComplete' });

  connectModelDelete(CourseTeacher, 'drop', { pattern: 'teachers/{id}', onSuccess: 'onDropped' });

  connectModelCreate(Period, 'create', { pattern: 'courses/{courseId}/periods', onSuccess: 'afterCreate' });
  connectModelUpdate(Period, 'save', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelDelete(Period, 'archive', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });
  connectModelUpdate(Period, 'unarchive', { pattern: 'periods/{id}', onSuccess: 'onApiRequestComplete' });

  connectModelRead(CourseScores, 'fetch',
    { pattern: 'courses/{courseId}/performance', onSuccess: 'onFetchComplete' });

  connectModelUpdate(TaskResult, 'acceptLate', { method: 'PUT', pattern: 'tasks/{id}/accept_late_work', onSuccess: 'onLateWorkAccepted' });

  connectModelUpdate(TaskResult, 'rejectLate', { method: 'PUT', pattern: 'tasks/{id}/reject_late_work', onSuccess: 'onLateWorkRejected' });

  connectModelRead(Job, 'requestJobStatus', { onSuccess: 'onJobUpdate', onFail: 'onJobUpdateFailure', pattern: 'jobs/{jobId}' });

  connectModelCreate(ScoresExport, 'create', { onSuccess: 'onCreated', pattern: 'courses/{course.id}/performance/export' });

  connectModelRead(TeacherTaskPlan, 'fetch', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}' });
  connectModelRead(TaskPlanStats, 'fetch', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}/stats' });

  connectModelRead(TaskPlanStats, 'fetchReview', { onSuccess: 'onApiRequestComplete', pattern: 'plans/{id}/review' });

  return connectModelRead(Courses.constructor, 'fetch', { onSuccess: 'onLoaded', url: 'user/courses' });
};

const BOOTSTRAPED_MODELS = {
  user:     User,
  courses:  Courses,
  payments: Payments,
  feature_flags: FeatureFlags,
};

const bootstrap = function(bootstrapData) {
  window._MODELS.bootstrapData = bootstrapData;
  for (let storeId in BOOTSTRAPED_MODELS) {
    const model = BOOTSTRAPED_MODELS[storeId];
    const data = bootstrapData[storeId];
    if (data) { model.bootstrap(data); }
  }
  return startAPI();
};

const start = function(bootstrapData) {
  return bootstrapData ? bootstrap(bootstrapData) : {};
};

export { startAPI, start };
<|endoftext|>


<commit_before>var React = require('react');
var blacklist = require('blacklist');

var FooterBar = React.createClass({
	getInitialState () {
		return {
			position: 'relative',
			width: 'auto',
			height: 'auto',
			top: 0
		};
	},
	componentDidMount () {
		// Bail in IE8 because React doesn't support the onScroll event in that browser
		// Conveniently (!) IE8 doesn't have window.getComputedStyle which we also use here
		if (!window.getComputedStyle) return;
		var footer = this.refs.footer;
		this.windowSize = this.getWindowSize();
		var footerStyle = window.getComputedStyle(footer);
		this.footerSize = {
			x: footer.offsetWidth,
			y: footer.offsetHeight + parseInt(footerStyle.marginTop || '0')
		};
		window.addEventListener('scroll', this.recalcPosition, false);
		window.addEventListener('resize', this.recalcPosition, false);
		this.recalcPosition();
	},
	getWindowSize () {
		return {
			x: window.innerWidth,
			y: window.innerHeight
		};
	},
	recalcPosition () {
		var wrapper = this.refs.wrapper;

		this.footerSize.x = wrapper.offsetWidth;

		var offsetTop = 0;
		var offsetEl = wrapper;

		while (offsetEl) {
			offsetTop += offsetEl.offsetTop;
			offsetEl = offsetEl.offsetParent;
		}

		var maxY = offsetTop + this.footerSize.y;
		var viewY = window.scrollY + window.innerHeight;

		var newSize = this.getWindowSize();
		var sizeChanged = (newSize.x !== this.windowSize.x || newSize.y !== this.windowSize.y);
		this.windowSize = newSize;

		var newState = {
			width: this.footerSize.x,
			height: this.footerSize.y
		};

		if (viewY > maxY && (sizeChanged || this.mode !== 'inline')) {
			this.mode = 'inline';
			newState.top = 0;
			newState.position = 'absolute';
			this.setState(newState);
		} else if (viewY <= maxY && (sizeChanged || this.mode !== 'fixed')) {
			this.mode = 'fixed';
			newState.top = window.innerHeight - this.footerSize.y;
			newState.position = 'fixed';
			this.setState(newState);
		}
	},
	render () {
		var wrapperStyle = {
			height: this.state.height,
			marginTop: 60,
			position: 'relative'
		};
		var footerProps = blacklist(this.props, 'children', 'style');
		var footerStyle = Object.assign(this.props.style || {}, {
			position: this.state.position,
			top: this.state.top,
			width: this.state.width,
			height: this.state.height
		});
		return (

{this.props.children}

		);
	}
});

module.exports = FooterBar;
<commit_msg>Remove direct mutation of props in `FooterBar`<commit_after>var React = require('react');
var blacklist = require('blacklist');

var FooterBar = React.createClass({
	getInitialState () {
		return {
			position: 'relative',
			width: 'auto',
			height: 'auto',
			top: 0
		};
	},
	componentDidMount () {
		// Bail in IE8 because React doesn't support the onScroll event in that browser
		// Conveniently (!) IE8 doesn't have window.getComputedStyle which we also use here
		if (!window.getComputedStyle) return;
		var footer = this.refs.footer;
		this.windowSize = this.getWindowSize();
		var footerStyle = window.getComputedStyle(footer);
		this.footerSize = {
			x: footer.offsetWidth,
			y: footer.offsetHeight + parseInt(footerStyle.marginTop || '0')
		};
		window.addEventListener('scroll', this.recalcPosition, false);
		window.addEventListener('resize', this.recalcPosition, false);
		this.recalcPosition();
	},
	getWindowSize () {
		return {
			x: window.innerWidth,
			y: window.innerHeight
		};
	},
	recalcPosition () {
		var wrapper = this.refs.wrapper;

		this.footerSize.x = wrapper.offsetWidth;

		var offsetTop = 0;
		var offsetEl = wrapper;

		while (offsetEl) {
			offsetTop += offsetEl.offsetTop;
			offsetEl = offsetEl.offsetParent;
		}

		var maxY = offsetTop + this.footerSize.y;
		var viewY = window.scrollY + window.innerHeight;

		var newSize = this.getWindowSize();
		var sizeChanged = (newSize.x !== this.windowSize.x || newSize.y !== this.windowSize.y);
		this.windowSize = newSize;

		var newState = {
			width: this.footerSize.x,
			height: this.footerSize.y
		};

		if (viewY > maxY && (sizeChanged || this.mode !== 'inline')) {
			this.mode = 'inline';
			newState.top = 0;
			newState.position = 'absolute';
			this.setState(newState);
		} else if (viewY <= maxY && (sizeChanged || this.mode !== 'fixed')) {
			this.mode = 'fixed';
			newState.top = window.innerHeight - this.footerSize.y;
			newState.position = 'fixed';
			this.setState(newState);
		}
	},
	render () {
		var wrapperStyle = {
			height: this.state.height,
			marginTop: 60,
			position: 'relative'
		};
		var footerProps = blacklist(this.props, 'children', 'style');
		var footerStyle = Object.assign({}, this.props.style || {}, {
			position: this.state.position,
			top: this.state.top,
			width: this.state.width,
			height: this.state.height
		});
		return (

{this.props.children}

		);
	}
});

module.exports = FooterBar;
<|endoftext|>


<commit_before>import {
  EditorPackage as TextureEditorPackage
} from 'substance-texture'

import ReproFigComponent from './ReproFigComponent'
import ReproFigPreview from './ReproFigPreview'
import InsertReproFigCommand from './InsertReproFigCommand'
import CellComponent from './CellComponent'
import CodeHighlightComponent from '../shared/CodeHighlightComponent'

import NullValueComponent from '../shared/NullValueComponent'
import BooleanValueComponent from '../shared/BooleanValueComponent'
import NumberValueComponent from '../shared/NumberValueComponent'
import IntegerValueComponent from '../shared/IntegerValueComponent'
import StringValueComponent from '../shared/StringValueComponent'
import ArrayValueComponent from '../shared/ArrayValueComponent'
import ObjectValueComponent from '../shared/ObjectValueComponent'
import TableValueComponent from '../shared/TableValueComponent'
import TestValueComponent from '../shared/TestValueComponent'
import ImageValueComponent from '../shared/ImageValueComponent'
import PlotlyValueComponent from '../shared/PlotlyValueComponent'

import {
  SetLanguageCommand, ToggleAllCodeCommand,
  HideCellCodeCommand, InsertCellCommand,
  ForceCellOutputCommand, RunCellCommand
} from './ArticleEditorCommands'

import FunctionUsageCommand from '../shared/FunctionUsageCommand'
import FunctionUsageTool from '../shared/FunctionUsageTool'

import AutoRunCommand from '../shared/AutoRunCommand'
import RunAllCommand from '../shared/RunAllCommand'

export default {
  name: 'editor',
  configure(config) {
    config.import(TextureEditorPackage)
    config.addComponent('cell', CellComponent)
    config.addComponent('code-highlight', CodeHighlightComponent)

    config.addComponent('value:null', NullValueComponent)
    config.addComponent('value:boolean', BooleanValueComponent)
    config.addComponent('value:integer', IntegerValueComponent)
    config.addComponent('value:number', NumberValueComponent)
    config.addComponent('value:string', StringValueComponent)
    config.addComponent('value:array', ArrayValueComponent)
    config.addComponent('value:object', ObjectValueComponent)
    config.addComponent('value:table', TableValueComponent)
    config.addComponent('value:test', TestValueComponent)
    config.addComponent('value:image', ImageValueComponent)
    config.addComponent('value:plotly', PlotlyValueComponent)

    config.addComponent('repro-fig', ReproFigComponent)
    config.addComponent('repro-fig-preview', ReproFigPreview)

    config.addCommand('insert-repro-fig', InsertReproFigCommand, {
      commandGroup: 'insert-repro-figure',
      nodeType: 'repro-fig'
    })
    config.addIcon('insert-repro-fig', { 'fontawesome': 'fa-area-chart' })
    config.addLabel('insert-repro-fig', 'Reproducible Figure')

    config.addCommand('insert-cell', InsertCellCommand, {
      nodeType: 'disp-quote',
      commandGroup: 'insert-cell-element'
    })
    config.addLabel('insert-cell', 'Cell')
    config.addKeyboardShortcut('CommandOrControl+Enter', { command: 'insert-cell' })

    config.addCommand('function-usage', FunctionUsageCommand, {
      commandGroup: 'prompt'
    })
    config.addTool('function-usage', FunctionUsageTool)

    config.addIcon('function-helper', {'fontawesome': 'fa-question-circle' })

    config.addIcon('insert-cell', { 'fontawesome': 'fa-plus-square' })

    config.addLabel('function-examples', {
      en: 'Example Usage'
    })
    config.addLabel('function-usage', {
      en: 'Syntax'
    })

    config.addCommand('auto-run', AutoRunCommand, {
      commandGroup: 'auto-run'
    })

    config.addCommand('run-all', RunAllCommand, {
      commandGroup: 'run-all'
    })
    config.addIcon('run-all', { 'fontawesome': 'fa-caret-square-o-right' })
    config.addLabel('run-all', 'Run All Code')
    config.addKeyboardShortcut('Shift+Enter+A', { command: 'run-all' })

    config.addToolPanel('toolbar', [
      {
        name: 'undo-redo',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['undo-redo']
      },
      {
        name: 'text-types',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'descriptive',
        commandGroups: ['text-types']
      },
      {
        name: 'annotations',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['formatting']
      },
      {
        name: 'additinal-tools',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['insert-figure', 'insert-repro-figure', 'insert-table', 'insert-cell-element']
      },
      {
        name: 'cell-execution',
        type: 'tool-group',
        showDisabled: false,
        style: 'minimal',
        commandGroups: ['run-all']
      },
      {
        name: 'cite',
        type: 'tool-dropdown',
        showDisabled: true,
        style: 'descriptive',
        commandGroups: ['insert-xref']
      },
      {
        name: 'view',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'descriptive',
        commandGroups: ['toggle-content-section', 'view']
      },
      {
        name: 'settings',
        type: 'tool-dropdown',
        showDisabled: true,
        style: 'descriptive',
        commandGroups: ['auto-run']
      }
    ])

    config.addToolPanel('node-menu', [
      {
        name: 'cell-actions',
        type: 'tool-group',
        style: 'descriptive',
        showDisabled: false,
        commandGroups: ['cell-actions']
      }
    ])

    /*
      Cell Actions
    */

    config.addCommand('run-cell-code', RunCellCommand, { commandGroup: 'cell-actions' })
    config.addCommand('hide-cell-code', HideCellCodeCommand, { commandGroup: 'cell-actions' })
    config.addCommand('force-cell-output', ForceCellOutputCommand, { commandGroup: 'cell-actions' })
    config.addCommand('set-mini', SetLanguageCommand, { language: 'mini', commandGroup: 'cell-actions' })
    config.addCommand('set-js', SetLanguageCommand, { language: 'js', commandGroup: 'cell-actions' })
    config.addCommand('set-py', SetLanguageCommand, { language: 'py', commandGroup: 'cell-actions' })
    config.addCommand('set-r', SetLanguageCommand, { language: 'r', commandGroup: 'cell-actions' })
    config.addCommand('set-sql', SetLanguageCommand, { language: 'sql', commandGroup: 'cell-actions' })

    // Labels and icons
    config.addLabel('run-cell-code', 'Run cell')
    config.addLabel('hide-cell-code', 'Hide code')
    config.addLabel('force-cell-output', 'Force output')
    config.addLabel('set-mini', 'Mini')
    config.addLabel('set-js', 'Javascript')
    config.addLabel('set-py', 'Python')
    config.addLabel('set-r', 'R')
    config.addLabel('set-sql', 'SQL')

    config.addIcon('ellipsis', { 'fontawesome': 'fa-ellipsis-v' })
    config.addIcon('test-failed', {'fontawesome': 'fa-times' })
    config.addIcon('test-passed', {'fontawesome': 'fa-check' })

    config.addLabel('show-all-code', 'Show All Code')
    config.addLabel('hide-all-code', 'Hide All Code')

    config.addLabel('settings', 'Settings')
    config.addLabel('auto-run', '${autoOrManual} Run Cells')

    // View Commands
    config.addCommand('hide-all-code', ToggleAllCodeCommand, {
      hideCode: true,
      commandGroup: 'view'
    })
    config.addCommand('show-all-code', ToggleAllCodeCommand, {
      hideCode: false,
      commandGroup: 'view'
    })

    config.addKeyboardShortcut('CommandOrControl+Alt+L', { command: 'show-all-code' })
    config.addKeyboardShortcut('CommandOrControl+Alt+O', { command: 'hide-all-code' })
  }
}
<commit_msg>Add keyboard shortcut for cell execution.<commit_after>import {
  EditorPackage as TextureEditorPackage
} from 'substance-texture'

import ReproFigComponent from './ReproFigComponent'
import ReproFigPreview from './ReproFigPreview'
import InsertReproFigCommand from './InsertReproFigCommand'
import CellComponent from './CellComponent'
import CodeHighlightComponent from '../shared/CodeHighlightComponent'

import NullValueComponent from '../shared/NullValueComponent'
import BooleanValueComponent from '../shared/BooleanValueComponent'
import NumberValueComponent from '../shared/NumberValueComponent'
import IntegerValueComponent from '../shared/IntegerValueComponent'
import StringValueComponent from '../shared/StringValueComponent'
import ArrayValueComponent from '../shared/ArrayValueComponent'
import ObjectValueComponent from '../shared/ObjectValueComponent'
import TableValueComponent from '../shared/TableValueComponent'
import TestValueComponent from '../shared/TestValueComponent'
import ImageValueComponent from '../shared/ImageValueComponent'
import PlotlyValueComponent from '../shared/PlotlyValueComponent'

import {
  SetLanguageCommand, ToggleAllCodeCommand,
  HideCellCodeCommand, InsertCellCommand,
  ForceCellOutputCommand, RunCellCommand
} from './ArticleEditorCommands'

import FunctionUsageCommand from '../shared/FunctionUsageCommand'
import FunctionUsageTool from '../shared/FunctionUsageTool'

import AutoRunCommand from '../shared/AutoRunCommand'
import RunAllCommand from '../shared/RunAllCommand'

export default {
  name: 'editor',
  configure(config) {
    config.import(TextureEditorPackage)
    config.addComponent('cell', CellComponent)
    config.addComponent('code-highlight', CodeHighlightComponent)

    config.addComponent('value:null', NullValueComponent)
    config.addComponent('value:boolean', BooleanValueComponent)
    config.addComponent('value:integer', IntegerValueComponent)
    config.addComponent('value:number', NumberValueComponent)
    config.addComponent('value:string', StringValueComponent)
    config.addComponent('value:array', ArrayValueComponent)
    config.addComponent('value:object', ObjectValueComponent)
    config.addComponent('value:table', TableValueComponent)
    config.addComponent('value:test', TestValueComponent)
    config.addComponent('value:image', ImageValueComponent)
    config.addComponent('value:plotly', PlotlyValueComponent)

    config.addComponent('repro-fig', ReproFigComponent)
    config.addComponent('repro-fig-preview', ReproFigPreview)

    config.addCommand('insert-repro-fig', InsertReproFigCommand, {
      commandGroup: 'insert-repro-figure',
      nodeType: 'repro-fig'
    })
    config.addIcon('insert-repro-fig', { 'fontawesome': 'fa-area-chart' })
    config.addLabel('insert-repro-fig', 'Reproducible Figure')

    config.addCommand('insert-cell', InsertCellCommand, {
      nodeType: 'disp-quote',
      commandGroup: 'insert-cell-element'
    })
    config.addLabel('insert-cell', 'Cell')
    config.addKeyboardShortcut('CommandOrControl+Enter', { command: 'insert-cell' })

    config.addCommand('function-usage', FunctionUsageCommand, {
      commandGroup: 'prompt'
    })
    config.addTool('function-usage', FunctionUsageTool)

    config.addIcon('function-helper', {'fontawesome': 'fa-question-circle' })

    config.addIcon('insert-cell', { 'fontawesome': 'fa-plus-square' })

    config.addLabel('function-examples', {
      en: 'Example Usage'
    })
    config.addLabel('function-usage', {
      en: 'Syntax'
    })

    config.addCommand('auto-run', AutoRunCommand, {
      commandGroup: 'auto-run'
    })

    config.addCommand('run-all', RunAllCommand, {
      commandGroup: 'run-all'
    })
    config.addIcon('run-all', { 'fontawesome': 'fa-caret-square-o-right' })
    config.addLabel('run-all', 'Run All Code')
    config.addKeyboardShortcut('Shift+Enter+A', { command: 'run-all' })

    config.addToolPanel('toolbar', [
      {
        name: 'undo-redo',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['undo-redo']
      },
      {
        name: 'text-types',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'descriptive',
        commandGroups: ['text-types']
      },
      {
        name: 'annotations',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['formatting']
      },
      {
        name: 'additinal-tools',
        type: 'tool-group',
        showDisabled: true,
        style: 'minimal',
        commandGroups: ['insert-figure', 'insert-repro-figure', 'insert-table', 'insert-cell-element']
      },
      {
        name: 'cell-execution',
        type: 'tool-group',
        showDisabled: false,
        style: 'minimal',
        commandGroups: ['run-all']
      },
      {
        name: 'cite',
        type: 'tool-dropdown',
        showDisabled: true,
        style: 'descriptive',
        commandGroups: ['insert-xref']
      },
      {
        name: 'view',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'descriptive',
        commandGroups: ['toggle-content-section', 'view']
      },
      {
        name: 'settings',
        type: 'tool-dropdown',
        showDisabled: true,
        style: 'descriptive',
        commandGroups: ['auto-run']
      }
    ])

    config.addToolPanel('node-menu', [
      {
        name: 'cell-actions',
        type: 'tool-group',
        style: 'descriptive',
        showDisabled: false,
        commandGroups: ['cell-actions']
      }
    ])

    /*
      Cell Actions
    */

    config.addCommand('run-cell-code', RunCellCommand, { commandGroup: 'cell-actions' })
    config.addCommand('hide-cell-code', HideCellCodeCommand, { commandGroup: 'cell-actions' })
    config.addCommand('force-cell-output', ForceCellOutputCommand, { commandGroup: 'cell-actions' })
    config.addCommand('set-mini', SetLanguageCommand, { language: 'mini', commandGroup: 'cell-actions' })
    config.addCommand('set-js', SetLanguageCommand, { language: 'js', commandGroup: 'cell-actions' })
    config.addCommand('set-py', SetLanguageCommand, { language: 'py', commandGroup: 'cell-actions' })
    config.addCommand('set-r', SetLanguageCommand, { language: 'r', commandGroup: 'cell-actions' })
    config.addCommand('set-sql', SetLanguageCommand, { language: 'sql', commandGroup: 'cell-actions' })

    // Labels and icons
    config.addLabel('run-cell-code', 'Run cell')
    config.addLabel('hide-cell-code', 'Hide code')
    config.addLabel('force-cell-output', 'Force output')
    config.addLabel('set-mini', 'Mini')
    config.addLabel('set-js', 'Javascript')
    config.addLabel('set-py', 'Python')
    config.addLabel('set-r', 'R')
    config.addLabel('set-sql', 'SQL')

    config.addIcon('ellipsis', { 'fontawesome': 'fa-ellipsis-v' })
    config.addIcon('test-failed', {'fontawesome': 'fa-times' })
    config.addIcon('test-passed', {'fontawesome': 'fa-check' })

    config.addLabel('show-all-code', 'Show All Code')
    config.addLabel('hide-all-code', 'Hide All Code')

    config.addLabel('settings', 'Settings')
    config.addLabel('auto-run', '${autoOrManual} Run Cells')

    // View Commands
    config.addCommand('hide-all-code', ToggleAllCodeCommand, {
      hideCode: true,
      commandGroup: 'view'
    })
    config.addCommand('show-all-code', ToggleAllCodeCommand, {
      hideCode: false,
      commandGroup: 'view'
    })

    config.addKeyboardShortcut('CommandOrControl+Alt+L', { command: 'show-all-code' })
    config.addKeyboardShortcut('CommandOrControl+Alt+O', { command: 'hide-all-code' })
    config.addKeyboardShortcut('Shift+Enter', { command: 'run-cell-code' })

  }
}
<|endoftext|>


<commit_before>'use strict';
var OdysseusLimiter = require('../index');
var redis = require('redis-mock');
var chai = require('chai');

chai.should();
var assert = chai.assert;

describe('store', function(){
    var store, app, redis_client;
    before(function () {
        redis_client = redis.createClient();
        store = new OdysseusLimiter.RedisStore({
            host: 'localhost',
            port: 6379
        });
        store.client = redis_client;
    });
    beforeEach(function () {
        redis_client.send_command('flushall', function (err, res) {
            if(err) throw err;
        })
    });
    describe('events', function(){
        it('should inherit from Store', function(){
            assert.instanceOf(store, OdysseusLimiter.Store);
            assert.instanceOf(store, require('events').EventEmitter);
        });
        it('should emit connect when connected', function(done){
            var mystore = new OdysseusLimiter.RedisStore({
                host: 'localhost',
                port: 6379
            });
            mystore.once('ready', function (error) {
                done();
            });
        });
        it('should emit error when there is error', function(done){
            var mystore = new OdysseusLimiter.RedisStore({
                host: 'localhost',
                port: 6379
            });
            mystore.once('error', function (error) {
                done();
            });
            mystore.emit('error', {message: 'error-mock'});
        });
        it('should emit request when new request is entered', function(done){
            store.once('request', function (request) {
                request instanceof Object ? done(): done({message: 'error in request event'})
            });
            store.addRequest({key: 'limit.store.requestEvent', ttl: 1000000});
        });
    });
    describe('request count', function(){
        it('should return 0 requests', function(done){
            store.getRequestCount('store.consistent.0', function (count) {
                count.should.equal(0);
                done();
            }, done);
        });
        it('should return 1 request', function(done){
            store.addRequest({key: 'store.consistent.1', ttl: 1000000}, function () {
                store.getRequestCount('store.consistent.1', function (count) {
                    count.should.equal(1);
                    done();
                }, done);
            }, done);
        });
    });
});<commit_msg>try to fix ready event<commit_after>'use strict';
var OdysseusLimiter = require('../index');
var redis = require('redis-mock');
var chai = require('chai');

chai.should();
var assert = chai.assert;

describe('store', function(){
    var store, app, redis_client;
    before(function () {
        store = new OdysseusLimiter.RedisStore({
            host: 'localhost',
            port: 6379
        });
    });
    beforeEach(function () {
        redis_client = redis.createClient();
        redis_client.send_command('flushall', function (err, res) {
            if(err) throw err;
        })
        store.client = redis_client;
    });
    describe('events', function(){
        it('should inherit from Store', function(){
            assert.instanceOf(store, OdysseusLimiter.Store);
            assert.instanceOf(store, require('events').EventEmitter);
        });
        it('should emit ready when connected', function(done){
            var mystore = new OdysseusLimiter.RedisStore({
                host: 'localhost',
                port: 6379
            });
            mystore.once('ready', function (error) {
                done();
            });
        });
        it('should emit error when there is error', function(done){
            var mystore = new OdysseusLimiter.RedisStore({
                host: 'localhost',
                port: 6379
            });
            mystore.once('error', function (error) {
                done();
            });
            mystore.emit('error', {message: 'error-mock'});
        });
        it('should emit request when new request is entered', function(done){
            store.once('request', function (request) {
                request instanceof Object ? done(): done({message: 'error in request event'})
            });
            store.addRequest({key: 'limit.store.requestEvent', ttl: 1000000});
        });
    });
    describe('request count', function(){
        it('should return 0 requests', function(done){
            store.getRequestCount('store.consistent.0', function (count) {
                count.should.equal(0);
                done();
            }, done);
        });
        it('should return 1 request', function(done){
            store.addRequest({key: 'store.consistent.1', ttl: 1000000}, function () {
                store.getRequestCount('store.consistent.1', function (count) {
                    count.should.equal(1);
                    done();
                }, done);
            }, done);
        });
    });
});<|endoftext|>


<commit_before>var KNOWN_APPS = {
    // MonoDev
    '00000000000000000000000000000002': {
        alias: ['monodev', 'md'],
        repo: 'git@github.com:jillix/MonoDev.git'
    },
    // DMS apps
    'cc36hf78HGT965HgtB96KJyg9dfGHtgV': {
        alias: ['cctool', 'cc'],
        repo: 'git@bitbucket.org:jillix/cctool.git'
    },
    'dms30dksd36V0a5PRPzXHgE49J5HlfHF': {
        alias: ['dms'],
        repo: 'git@bitbucket.org:jillix/dms.git'
    },
    'crm6hf78HGT965HgtB96KJyg9dfGHtgV': {
        alias: ['crm'],
        repo: 'git@bitbucket.org:jillix/crm.git'
    },
    'cv46hf78HGI965HgtB96KJyg9dfGHtgV': {
        alias: ['cv'],
        repo: 'git@bitbucket.org:jillix/campaignverification.git'
    },
    'webSockets790R6EAUMZ08UXRHDAZUTW': {
        alias: ['ws'],
        repo: 'git@bitbucket.org:IonicaBizau/websockets.git'
    },
    // old apps
    '00000000000000000000000000000109': {
        alias: ['ladivina', 'ld'],
        repo: 'git@bitbucket.org:jillix/ladivina.git'
    },
    '00000000000000000000000000000100': {
        alias: ['partnerlogin', 'pl'],
        repo: 'git@bitbucket.org:jillix/partnerlogin.git'
    },
    '00000000000000000000000000000108': {
        alias: ['salongenf', 'sg'],
        repo: 'git@bitbucket.org:jillix/salongenf.git'
    },
    '00000000000000000000000000000101': {
        alias: ['aktionshop', 'as'],
        repo: 'git@bitbucket.org:jillix/aktionshop.git'
    },
    '00000000000000000000000000000051': {
        alias: ['liqshoporders', 'lo'],
        repo: 'git@bitbucket.org:jillix/liqshoporders.git'
    }
};

function find(app) {
    for (var i in KNOWN_APPS) {
        for (var a in KNOWN_APPS[i].alias) {
            if (KNOWN_APPS[i].alias[a] === app.toLowerCase()) {
                return { id: i, repo: KNOWN_APPS[i].repo };
            }
        }
    }
}

exports.KNOWN_APPS = KNOWN_APPS;
exports.find = find;

<commit_msg>Corrected the git provider name.<commit_after>var KNOWN_APPS = {
    // MonoDev
    '00000000000000000000000000000002': {
        alias: ['monodev', 'md'],
        repo: 'git@github.com:jillix/MonoDev.git'
    },
    // DMS apps
    'cc36hf78HGT965HgtB96KJyg9dfGHtgV': {
        alias: ['cctool', 'cc'],
        repo: 'git@bitbucket.org:jillix/cctool.git'
    },
    'dms30dksd36V0a5PRPzXHgE49J5HlfHF': {
        alias: ['dms'],
        repo: 'git@bitbucket.org:jillix/dms.git'
    },
    'crm6hf78HGT965HgtB96KJyg9dfGHtgV': {
        alias: ['crm'],
        repo: 'git@bitbucket.org:jillix/crm.git'
    },
    'cv46hf78HGI965HgtB96KJyg9dfGHtgV': {
        alias: ['cv'],
        repo: 'git@bitbucket.org:jillix/campaignverification.git'
    },
    'webSockets790R6EAUMZ08UXRHDAZUTW': {
        alias: ['ws'],
        repo: 'git@github.com:IonicaBizau/WebSockets.git'
    },
    // old apps
    '00000000000000000000000000000109': {
        alias: ['ladivina', 'ld'],
        repo: 'git@bitbucket.org:jillix/ladivina.git'
    },
    '00000000000000000000000000000100': {
        alias: ['partnerlogin', 'pl'],
        repo: 'git@bitbucket.org:jillix/partnerlogin.git'
    },
    '00000000000000000000000000000108': {
        alias: ['salongenf', 'sg'],
        repo: 'git@bitbucket.org:jillix/salongenf.git'
    },
    '00000000000000000000000000000101': {
        alias: ['aktionshop', 'as'],
        repo: 'git@bitbucket.org:jillix/aktionshop.git'
    },
    '00000000000000000000000000000051': {
        alias: ['liqshoporders', 'lo'],
        repo: 'git@bitbucket.org:jillix/liqshoporders.git'
    }
};

function find(app) {
    for (var i in KNOWN_APPS) {
        for (var a in KNOWN_APPS[i].alias) {
            if (KNOWN_APPS[i].alias[a] === app.toLowerCase()) {
                return { id: i, repo: KNOWN_APPS[i].repo };
            }
        }
    }
}

exports.KNOWN_APPS = KNOWN_APPS;
exports.find = find;

<|endoftext|>


<commit_before>"use strict";

var detector = module.exports = {};

detector.isIE = function(version) {
    function isAnyIeVersion() {
        var agent = navigator.userAgent.toLowerCase();
        return agent.indexOf("msie") !== -1 || agent.indexOf("trident") !== -1;
    }

    if(!isAnyIeVersion()) {
        return false;
    }

    if(!version) {
        return true;
    }

    //Shamelessly stolen from https://gist.github.com/padolsey/527683
    var ieVersion = (function(){
        var undef,
            v = 3,
            div = document.createElement("div"),
            all = div.getElementsByTagName("i");

        do {
            div.innerHTML = "";
        }
        while (all[0]);

        return v > 4 ? v : undef;
    }());

    return version === ieVersion;
};

detector.isLegacyOpera = function() {
    return !!window.opera;
};
<commit_msg>Handle Edge as an IE browser.<commit_after>"use strict";

var detector = module.exports = {};

detector.isIE = function(version) {
    function isAnyIeVersion() {
        var agent = navigator.userAgent.toLowerCase();
        return agent.indexOf("msie") !== -1 || agent.indexOf("trident") !== -1 || agent.indexOf(" edge/") !== -1;
    }

    if(!isAnyIeVersion()) {
        return false;
    }

    if(!version) {
        return true;
    }

    //Shamelessly stolen from https://gist.github.com/padolsey/527683
    var ieVersion = (function(){
        var undef,
            v = 3,
            div = document.createElement("div"),
            all = div.getElementsByTagName("i");

        do {
            div.innerHTML = "";
        }
        while (all[0]);

        return v > 4 ? v : undef;
    }());

    return version === ieVersion;
};

detector.isLegacyOpera = function() {
    return !!window.opera;
};
<|endoftext|>