<commit_before>/* PAGE is way of organizing your javascript based app.
* Works great across pages, or in single page apps, extensions, etc etc.
* Works great with other libraries like jQuery.
* Can be extended to work great with other libraries
* Small by design.
* SEE https://github.com/dogstyle/page
* MIT License
*/
var PAGE = (function() {

	/*
	* the poing of PAGE is to be able to open up a javascript console, type PAGE
	* and see everything you've loaded into your page.
	*
	* try it, it's cool.
	*
	* because PAGE is a singleton, it doesn't really matter if methods are added to the prototype or the instance.
	* However, in the console, there is a nice seperation between the instance methods and the prototype methods.
	* So, for this reason alone I have seperated them.
	*
	* to add more functionality to PAGE itself, use PAGE.extend(function(puppy, dog, log)
	* to add more instance properties use PAGE.add("GROUPNAME.THING", THING)
	*
	* to retrieve either use PAGE.wait
	* for instance properties PAGE.wait("GROUPNAME.THING", function(THING) {})
	* for prototype PAGE.wait("THING", function(THING) {})
	*
	* For most things, PAGE.add, PAGE.add$, and PAGE.wait or all you need.
	*
	* for example, adding a function
	* PAGE.add("Functions.myFunction", function() {
	* alert("dog is great!")
	* })
	*
	* for example, a singleton
	* PAGE.add("Modules.myModule", (function() {
	* var dog = {}
	* return dog
	* })())
	*
	* for example, a constructor
	* PAGE.add("Constructors.MyConstructor", function() {
	* var dog = {
	*  love : "trucks"
	* }
	* function init() {
	* alert("dogs love " + dog.love)
	* }
	* init()
	* return dog
	* })
	*
	*/
	var Page  = function(){}          // base constructor
		, dog   = Page.prototype = {}   // base prototype
		, puppy = new Page()            // base instance
		, interval = undefined          // timing

	/* logging for everything, gets passed into extend */
	function log(thing) {
		if (typeof console === "object") {
			console.log(thing)
		}
	}

	/* this is how you add stuff to your app,
	* example usage:
	* PAGE.add("Constructors.MyConstructor", function($root, options) {
	* ...
	* })
	* */
	dog.add = function(path, obj, test) {
		if (typeof path === "undefined") return
		var arr = path.split(".")
		if (arr.length < 2) return
		var group = arr[0]
			, item = arr[1]
		if (!puppy[group]) puppy[group] = {}
		return puppy[group][item] = obj
	}

	/* this is how to wait for methods that have been added using extend
	* use PAGE.wait() instead
	* might be useful while extending the functionality PAGE itself
	* example usage:
	* PAGE.waitProto("Image", function(Image) {
	* var image = Image
	* })
	* */
	dog.waitProto = function(name, callback) {
		var limit = 1000
			, count = 0
			, interval

		if (dog[name]) {
			return callback(dog[name])
		}

		interval = setInterval(function() {
			if (count > limit) {
				console.error("could not find prototype " + name)
				clearInterval(interval)
				return
			}
			if (count > limit || (dog[name])) {
				if (typeof callback === "function") {
					callback(dog[name])
				}
				clearInterval(interval)
			}
			count++
		}, 10)
	}

	/* the base of PAGE.wait(...)
	* example usage :
	* PAGE.waitLoad("Constructors", "Popup", function(Popup) {
	* ...
	* }) */
	dog.waitLoad = function(group, name, callback) {
			var limit = 1000
				, count = 0
				, interval

			if (puppy[group] && puppy[group][name]) {
				return callback(puppy[group][name])
			}

			interval = setInterval(function() {
				if (count > limit) {
					debugger
					console.error("could not find " + group + ":" + name)
					clearInterval(interval)
					return
				}
				if (count > limit || (puppy[group] && puppy[group][name])) {
					if (typeof callback === "function") {
						callback(puppy[group][name])
					}
					clearInterval(interval)
				}
				count++
			}, 10)
		}

	/* the shorthand of PAGE.wait(...)
	* example usage :
	* PAGE.wait("Constructors.Popup", function(Popup) {
	* ...
	* }) */
	dog.wait = function(path, callback) {
		if (typeof path === "undefined") return
		var arr = path.split(".")
		if (arr.length < 1) return
		if (arr.length < 2) return dog.waitProto(arr[0], callback)
		return dog.waitLoad(arr[0], arr[1], callback)
	}

	/* this is for extending the PAGE class itself, giving access to the prototype
	* example usage
	* PAGE.extend(function( instance, proto, log ) {
	* proto.Image = {
	*   upload : function() {}
	* }
	* }) */
	dog.extend = function(callback) {
		typeof callback === "function" && callback(puppy, dog, log)
	}

	/* special case for adding stuff after jquery has loaded, we all love jquery!
	* example usage :
	* PAGE.add$("Modules.myPage", (function() {
	* ...
	* }()))
	* */
	dog.add$ = function() {
		var args = arguments
		try {
			$(document).ready(function() {
				dog.add.apply(puppy, args)
			})
		}
		catch (ex) {
			throw(ex)
		}
	}

	/* immediate check to see if something exists, if so, return it, otherwise return undefined
	* example usage
	* var shoppingCart = PAGE.exists("Properties.ShoppingCart")
	*/
	dog.exists = function (path) {
		if (typeof path === "undefined") return
		var arr = path.split(".")
			, x = 0
			, obj = puppy

		if (arr.length < 1) return

		while (x < arr.length) {
			obj = obj[arr[x]]
			if (obj === undefined) return obj
			x++
		}
		return obj
	}

	/* returns an empty object, when it's finished loading asynchronously, the returned object gets changed to the finished object
	* This is dangerous practice, so be careful. Don't expect the object returned to behave the way intended. check for wait if you don't know for sure
	* example usage
	* var popupCode = PAGE.get("Constructors.Popup")
	*   , someFunction = PAGE.get("Functions.someFunction")
	*
	* // checking to see it's loaded, if it wait as a property, then it's not done (unless of course the thing you are trying to return also has a wait property.... presents a curious puzzle, bah)
	* if (!someFunction.wait) someFunction()
	*
	*/
	dog.get = function(path) {
		var _this = { wait : true }
		dog.wait(path, function(f) {
			_this = f
		})
		return _this
	}

	return puppy

}())
<commit_msg>simplified mapArguments<commit_after>/* PAGE is way of organizing your javascript based app.
* Works great across pages, or in single page apps, extensions, etc etc.
* Works great with other libraries like jQuery.
* Small by design.
* SEE https://github.com/dogstyle/page
* Created by Justin Kempton
* MIT License
*/
;(function() {

var PAGE = (function() {

	/*
	* the point of PAGE is to be able to open up a javascript console, type PAGE and see everything you've loaded.
	* For large complex projects this can be very helpful during the debugging process.
	* In addition, with PAGE.test.js, you have an easy integrated code coverage testing
	*
	* For most things, PAGE.add, PAGE.add$, and PAGE.wait are all you need.
	*
	* To add to your PAGE object use PAGE.add("GROUPNAME.THING", THING)
	*
	* Example:
	* PAGE.add("Constructors.MyThing", function(options) {
	* var dog = {}
	* return dog
	* })
	*
	* to retrieve instance items use PAGE.wait
	* for instance properties PAGE.wait("GROUPNAME.THING", function(THING) {})
	* for prototype PAGE.wait("THING", function(THING) {})
	*
	* To add more functionality to PAGE itself, use PAGE.extend(function(puppy, dog, log)
	* Puppy is the instance, Dog is the Prototype, and Log is for logging.
	*
	* for example, adding a function
	* PAGE.add("Functions.myFunction", function() {
	* alert("dog is great!")
	* })
	*
	* for example, a singleton, what I commonly call 'Modules'
	* PAGE.add("Modules.myModule", (function() {
	* var dog = {}
	* return dog
	* })())
	*
	* for example, a constructor
	* PAGE.add("Constructors.MyConstructor", function() {
	* var dog = {
	*  love : "trucks"
	* }
	* function init() {
	* alert("dogs love " + dog.love)
	* }
	* init()
	* return dog
	* })
	*
	*/
	var Page  = function(){}          // base constructor
		, dog   = Page.prototype = {}   // base prototype
		, puppy = new Page()            // base instance
		, speedOfInterval = 150         // speed of interval
		, waitList = dog.waitList = {}  // list of things added
		, finishedCallbacks = []        // array of callbacks to run when everything is loaded
		, done = dog.done = function(func) { // method to add to finished callback
			finishedCallbacks.push(func)
		}

	/* internal function calling all done callbacks when everything is finished loading */
	function runFinishedCallbacks() {
		if (checkWaitingList()) return
		for(var x in finishedCallbacks) finishedCallbacks[x](puppy, dog, log)
	}

	/* methods for checking if finished loading */
	function checkWaitingList() {
		var count = 0
		for(var x in waitList) if (!waitList[x]) count++
		return count
	}

	/* logging for everything, gets passed into extend */
	var log = dog.log = function(thing) {
		if (typeof console === "object") {
			console.log(thing)
		}
	}

	/* this is the method to add stuff to your app,
	* example usage:
	* PAGE.add("Constructors.MyConstructor", function($root, options) {
	* ...
	* })
	* */
	dog.add = function(path, obj) {
		if (typeof path === "undefined") return
		var arr = path.split(".")
		if (arr.length < 2) return
		var group = arr[0]
			, item = arr[1]
		if (!puppy[group]) puppy[group] = {}
		return puppy[group][item] = obj
	}

	/* this is a base method for returning prototype
	* use PAGE.wait() instead
	* might be useful while extending the functionality PAGE itself
	* example usage:
	* PAGE.waitProto("Image", function(Image) {
	* var image = Image
	* })
	* */
	dog.waitProto = function(name, callback) {
		var limit = 100
			, count = 0
			, interval

		waitList[name] = false

		if (dog[name]) {
			waitList[name] = true
			return callback(dog[name])
		}

		interval = setInterval(function() {
			if (count > limit) {
				console.error("could not find prototype " + name)
				clearInterval(interval)
				return
			}
			if (dog[name]) {
				if (typeof callback === "function") {
					callback(dog[name])
				}
				waitList[name] = true
				clearInterval(interval)
				runFinishedCallbacks()
			}
			count++
		}, speedOfInterval)
	}

	/* the base of PAGE.wait(...)
	* example usage :
	* PAGE.waitLoad("Constructors", "Popup", function(Popup) {
	* ...
	* }) */
	dog.waitLoad = function(group, name, callback, refObj) {
		var limit = 100 // number of tries (multiply by interval to get time in miliseconds
			, count = 0
			, interval

		refObj = refObj || {}

		waitList[group + "." + name] = false

		if (puppy[group] && puppy[group][name]) {
			waitList[group + "." + name] = true
			return callback(puppy[group][name])
		}

		interval = setInterval(function() {
			if (count > limit) {
				debugger
				console.error("could not find " + group + ":" + name)
				clearInterval(interval)
				return
			}
			if (count > limit || (puppy[group] && puppy[group][name])) {
				if (typeof callback === "function") {
					refObj[name] = puppy[group][name]
					callback(puppy[group][name])
				}
				waitList[group + "." + name] = true
				clearInterval(interval)
				runFinishedCallbacks()
			}
			count++
		}, speedOfInterval)
	}

	/* method for loading external js scripts, used for testing,
	* production code should be loading as minified unified code */
	dog.loadScript = function(pathToFile) {
		var scriptId = pathToFile.replace(/\./g,"_")
			, existingElm = document.getElementById(scriptId)

		if (existingElm) {
			existingElm.parentElement.removeChild(existingElm)
		}

		var fileref = document.createElement('script')
		fileref.setAttribute("type","text/javascript")
		fileref.setAttribute("src", pathToFile + "?" + (String(Math.random()).replace(/\./,""))) // randomize
		fileref.setAttribute("id", scriptId)
		document.getElementsByTagName("head")[0].appendChild(fileref)
	}

	/* method for loading external libries, that get dumped into the PAGE.Lib object.
	* loaded scripts must be added to the window object, and the name must be set in the globalVarName
	* Use for testing. Production code should load as bundled minified code */
	dog.AddExternalLib = function(path, globalVarName, callback) {

		if (dog.exists("Lib." + globalVarName)) {
			typeof callback === "function" && callback(window[globalVarName])
			return
		}

		dog.loadScript(path)
		var interval = setInterval(function() {
			var glob = window[globalVarName]
			if (glob) {
				clearInterval(interval)
				if (!puppy.Lib) puppy.Lib = {}
				puppy.add("Lib." + globalVarName, glob)
				typeof callback === "function" && callback(glob)
			}
		}, 100)
	}

	/* the shorthand of PAGE.waitLoad(...)
	* example usage :
	* PAGE.wait("Constructors.Popup", function(Popup) {
	* ...
	* })
	* alternatively
	* This adds it to the refObj
	* PAGE.wait("Constructors.Popup", callback, refObj)
	*
	* */
	dog.wait = function(path, callback, refObj) {
		refObj = refObj || {}
		if (typeof path === "undefined") return
		var arr = path.split(".")
		if (arr.length < 1) return
		if (arr.length < 2) return dog.waitProto(arr[0], callback)
		return dog.waitLoad(arr[0], arr[1], callback, refObj)
	}

	/* take a path and check against a the global window variable by default, or set in another variable
	*
	* for example: waiting for a jquery addon to load
	* PAGE.waitWindow("jQuery.fn.SomeAddon", true, function() {
	*     ... your code here
	* })
	*
	* will add the following as soon as it's finished loading
	* PAGE.Lib.SomeAddon
	*
	* by passing in a object, when it's ready, callback returns it
	 * add is boolean and optional, add it to the Lib
	 * callback is function and optional returns the thing */
	dog.waitWindow = function(path, add, obj, callback) {
		var map = mapArguments(arguments)
		if (map.Fun) callback = map.Fun[0]
		if (map.Boo) add = map.Boo[0]
		if (map.Str) path = map.Str[0]
		if (map.Obj) obj = map.Obj[0]
		else obj = window

		var name = path.split(".").reverse()[0]
			, glob = dog.exists(path, obj)

		if (glob) {
			callback(glob)
			if (add) {
				if (!puppy.Lib) puppy.Lib = {}
				puppy.add("Lib." + name, glob)
			}
			return glob
		}

		var interval = setInterval(function() {
			glob = dog.exists(path, obj)
			if (glob) {
				clearInterval(interval)
				if (add) {
					if (!puppy.Lib) puppy.Lib = {}
					puppy.add("Lib." + name, glob)
				}
				callback(glob)
			}
		}, 100)
	}

	/* add a whole bunch of global variables to the PAGE.Lib, return when they are done loading */
	dog.batchWaitWindow = function(path, path, arr, path, add, callback) {
		var waitCount = 1
			, paths = []
			, obj = window

		callback = function(){}

		function finished() {
			waitCount -= 1
			if (!waitCount) callback(PAGE.Lib)
		}

		var map = mapArguments(arguments)
		if (map.Fun) callback = map.Fun[0]
		if (map.Boo) add = map.Boo[0]
		else add = true
		if (map.Obj) obj = map.Obj[0]
		if (map.Arr) {
			for(var x in map.Arr) paths = paths.concat( map.Arr[x] )
		}
		if (map.Str) paths = paths.concat(map.Str)

		waitCount = paths.length

		for(var y in paths) {
			dog.waitWindow(paths[y], add, obj, finished)
		}
	}

	/* this is for extending the PAGE class itself, giving access to the prototype
	* example usage
	* PAGE.extend(function( instance, proto, log ) {
	* proto.Image = {
	*   upload : function() {}
	* }
	* }) */
	dog.extend = function extend(callback) {
		typeof callback === "function" && callback(puppy, dog, log)
	}

	/* special case for adding stuff after jquery has loaded, we all love jquery!
	* example usage :
	* PAGE.add$("Modules.myPage", (function() {
	* ...
	* }()))
	* */
	dog.add$ = function() {
		var args = arguments
			, ret = {}
		try {
			$(document).ready(function() {
				ret = dog.add.apply(puppy, args)
			})
		}
		catch (ex) {
			throw(ex)
		}
		return ret
	}

	/* immediate check to see if something exists, if so, return it, otherwise return undefined
	* example usage
	* var shoppingCart = PAGE.exists("Properties.ShoppingCart")
	*/
	dog.exists = function (path, base) {
		if (typeof path === "undefined") return
		var arr = path.split(".")
			, x = 0
			, obj = base || puppy

		if (arr.length < 1) return

		while (x < arr.length) {
			obj = obj[arr[x]]
			if (obj === undefined) return obj
			x++
		}
		return obj
	}

	/* Load a whole batch of things, pass in array and object, object gets filled by things (by reference), or optionally calls back with the object when it's done. */
	dog.batchWaitRef = function(arr, ref, callback) {
		var count = 0
			, ref = ref || {}
		for (var x = 0; x < arr.length; x++) {
			;(function(index, arr) {
				dog.wait(arr[index], function(f) {
					count += 1
					var name = arr[index].split(".").reverse()[0]
					ref[name] = f
					if (count >= arr.length) {
						typeof callback === "function" && callback(ref)
					}
				})
			}(x, arr))
		}
		return puppy
	}

	dog.batchWait = function(str, str, str, obj, callback) {
		var args = arguments
			, arr = []
			, ref
			, x
			, callback
			, map = {}

		for(x in arguments) {
			if (typeof arguments[x] === "string") arr.push(arguments[x])
				if (typeof arguments[x] === "object") {
					if (arguments[x].constructor === Array) {
						arr = arr.concat(arguments[x])
					} else {
						ref = arguments[x]
					}
				}
			if (typeof arguments[x] === "function") callback = arguments[x]
		}

		if (!ref) ref = {}

		dog.batchWaitRef(arr, ref, callback)
	}

	/* basic method to hide the PAGE object from prying eyes, should be called on done.
	* But it could be called multiple times, and with complex logic, that when minified will make it tough for
	* some kind of hacker to understand what your code is doing. Then again, it's javascript, everything is available
	* so if you really want security, protect the server side code.
	*
	* PAGE.done(function() {
	*   PAGE.stash("secretName")
	* })
	*/
	dog.stash = function(key) {
		if (key) window[key] = puppy
		if (!dog.pointers) dog.pointers = {}
		else {
			for(var x in dog.pointers) delete window[x]
		}
		dog.pointers[key] = true
		delete window.PAGE
		return puppy
	}

	/* use to map arguments, also used by my methods */
	dog.Helpers = {
		mapArguments : function(args) { return {} }
	}

	var mapArguments = dog.Helpers.mapArguments = function(args) {
		var map = {}
		, type

		function pushIn(name, item) {
			name = name.substr(0,1).toUpperCase() + name.substr(1,2)
			if (!map[name]) map[name] = []
			map[name].push(item)
		}

		for(var y = 0; y < args.length; y++) {
			type = typeof args[y]

			if (type === "object") {
				if (args[y] === null) {
					pushIn("nul", args[y])
					continue
				}
				if (args[y].constructor === Array) {
					pushIn("arr", args[y])
					continue
				}
				if  (args[y] instanceof Error) {
					pushIn("err", args[y])
					continue
				}
			}
			pushIn(type, args[y])
		}

		return map
	}

	return puppy

}())

window.PAGE = PAGE

}())

<|endoftext|>


<commit_before>(function () {
    var oppressor = {
        // FIXME: need both boss HPs
        bossName: "Oppressor",
        areaSeal: "Hangar 8",
        phases: [
            {
                title: "Phase 1 (burn)",
                loop: false,
                endSeconds: 90,
                rotation: [
                    { name: "Royal Fount", time: 7 },
                    { name: "Prey", time: 12 },
                    //{ name: "Hydrothermal Missile", time: 15 },
                    { name: "Gunnery Pod", time: 19 },
                    { name: "Photon Spaser", time: 22 },
                    { name: "Royal Fount", time: 27 },
                    { name: "Resin Bomb", time: 35 },
                    { name: "Photon Spaser", time: 42 },
                    { name: "Gunnery Pod", time: 47 },
                    { name: "Royal Fount", time: 49 },
                    { name: "Emergency Deployment", time: 52 },
                    { name: "Prey", time: 57 },
                    //{ name: "Hydrothermal Missile", time: 60 },
                    { name: "Gunnery Pod", time: 64 },
                    { name: "Royal Fount", time: 67 },
                    { name: "Photon Spaser", time: 74 },
                    { name: "Royal Fount", time: 84 },
                    { name: "Distress Signal", time: 87 },
                ],
            },
            {
                title: "Phase 2 (split)",
                loop: true,
                loopSeconds: 120,
                rotation: [
                    { name: "Quick Landing", time: 2 , skipFirst: true},
                    //{ name: "3000-tonze Missile", time: 15 },
                    { name: "Gunnery Pod", time: 24 },
                    { name: "Emergency Deployment", time: 27 },
                    { name: "Resin Bomb", time: 35 },
                    { name: "Royal Fount", time: 40 },
                    { name: "Photon Spaser", time: 42 },
                    { name: "Double Prey", time: 49 },
                    //{ name: "Hydrothermal Missile", time: 52 },
                    { name: "Royal Fount", time: 60 },
                    { name: "Hypercompressed Plasma", time: 66 },
                    { name: "(bomb touchdown)", time: 70 },
                    { name: "Photon Spaser", time: 75 },
                    { name: "Gunnery Pod", time: 85 },
                    { name: "Royal Fount", time: 94 },
                    { name: "(takeoff)", time: 100 },
                    { name: "(stack for schmutz)", time: 105 },
                    { name: "(1st schmutz)", time: 112 },
                    { name: "(8th schmutz)", time: 120 },
                ],
            },
        ],
    };

    var AlexanderSavageTurn1 = function () {
        BaseTickable.apply(this, arguments);
        this.zoneFilter = "Alexander - The Fist of the Father (Savage)";
        this.bosses = [oppressor];
    };
    AlexanderSavageTurn1.prototype = new BaseTickable;

    updateRegistrar.register(new AlexanderSavageTurn1());
})();<commit_msg>Add alternate zone for savage A1<commit_after>(function () {
    var oppressor = {
        // FIXME: need both boss HPs
        bossName: "Oppressor",
        areaSeal: "Hangar 8",
        phases: [
            {
                title: "Phase 1 (burn)",
                loop: false,
                endSeconds: 90,
                rotation: [
                    { name: "Royal Fount", time: 7 },
                    { name: "Prey", time: 12 },
                    //{ name: "Hydrothermal Missile", time: 15 },
                    { name: "Gunnery Pod", time: 19 },
                    { name: "Photon Spaser", time: 22 },
                    { name: "Royal Fount", time: 27 },
                    { name: "Resin Bomb", time: 35 },
                    { name: "Photon Spaser", time: 42 },
                    { name: "Gunnery Pod", time: 47 },
                    { name: "Royal Fount", time: 49 },
                    { name: "Emergency Deployment", time: 52 },
                    { name: "Prey", time: 57 },
                    //{ name: "Hydrothermal Missile", time: 60 },
                    { name: "Gunnery Pod", time: 64 },
                    { name: "Royal Fount", time: 67 },
                    { name: "Photon Spaser", time: 74 },
                    { name: "Royal Fount", time: 84 },
                    { name: "Distress Signal", time: 87 },
                ],
            },
            {
                title: "Phase 2 (split)",
                loop: true,
                loopSeconds: 120,
                rotation: [
                    { name: "Quick Landing", time: 2 , skipFirst: true},
                    //{ name: "3000-tonze Missile", time: 15 },
                    { name: "Gunnery Pod", time: 24 },
                    { name: "Emergency Deployment", time: 27 },
                    { name: "Resin Bomb", time: 35 },
                    { name: "Royal Fount", time: 40 },
                    { name: "Photon Spaser", time: 42 },
                    { name: "Double Prey", time: 49 },
                    //{ name: "Hydrothermal Missile", time: 52 },
                    { name: "Royal Fount", time: 60 },
                    { name: "Hypercompressed Plasma", time: 66 },
                    { name: "(bomb touchdown)", time: 70 },
                    { name: "Photon Spaser", time: 75 },
                    { name: "Gunnery Pod", time: 85 },
                    { name: "Royal Fount", time: 94 },
                    { name: "(takeoff)", time: 100 },
                    { name: "(stack for schmutz)", time: 105 },
                    { name: "(1st schmutz)", time: 112 },
                    { name: "(8th schmutz)", time: 120 },
                ],
            },
        ],
    };

    var AlexanderSavageTurn1 = function () {
        BaseTickable.apply(this, arguments);
        this.zoneFilter = "Alexander - The Fist of the Father (Savage)";
        this.bosses = [oppressor];
    };
    AlexanderSavageTurn1.prototype = new BaseTickable;

    updateRegistrar.register(new AlexanderSavageTurn1());

    var alex1_unknown = new AlexanderSavageTurn1();
    alex1_unknown.zoneFilter = "Unknown Zone (1C1)";
    updateRegistrar.register(alex1_unknown);
})();<|endoftext|>


<commit_before>!(function (root) {

    var tmpl_cache = {};
    var compiled_temp = {};
    var resp_cache = {};
    var quikr = {
        cache_time: 5000,
        tmpl: function tmpl(str, data, option_id) {
            // Figure out if we're getting a template, or if we need to
            // load the template - and be sure to cache the result.
            var fn = !/\W/.test(str) ?
                tmpl_cache[str] = tmpl_cache[str] ||
                    this.tmpl(document.getElementById(str).innerHTML) :
                // Generate a reusable function that will serve as a template
                // generator (and which will be cached).
                new Function("obj",
                    "var p=[],print=function(){p.push.apply(p,arguments);};" +

                    // Introduce the data as local variables using with(){}
                    "with(obj){p.push('" +

                    // Convert the template into pure JavaScript
                    str
                        .replace(/[\r\t\n]/g, " ")
                        .split("<%").join("\t")
                        .replace(/((^|%>)[^\t]*)'/g, "$1\r")
                        .replace(/\t=(.*?)%>/g, "',$1,'")
                        .split("\t").join("');")
                        .split("%>").join("p.push('")
                        .split("\r").join("\\'")
                    + "');}return p.join('');");

            if (option_id) {
                tmpl_cache[option_id] = fn;
            }
            // Provide some basic currying to the user
            return data ? fn(data) : fn;
        },
        get: function (url, data) {
            if (typeof this._urls_[url] == "function") {
                var resp = this._urls_[url](data);
                if (typeof resp.done == "function") {
                    return resp;
                } else {
                    return jQuery.Deferred(function ($d) {
                        $d.resolve(resp);
                    }).promise();
                }
            } else {
                var cache_url = url + ((url.indexOf("?") > -1) ? "&" : "?") + jQuery.param(data);
                if (resp_cache[cache_url] && resp_cache[cache_url].timestamp > new Date().getTime()) {
                    return resp_cache[cache_url].$req
                }
                resp_cache[cache_url] = {
                    timestamp: new Date().getTime() + this.cache_time,
                    $req: jQuery.get(url, data)
                };
                return resp_cache[cache_url].$req;
            }
        },
        _actions_: {},
        action: function (action, callback) {
            this._actions_[action] = callback;
            return this;
        },
        _urls_: {},
        url: function (url, callback) {
            this._urls_[url] = callback;
            return this;
        },
        applyTmpl: function (elem, rawdata) {
            var url = elem.getAttribute("url");
            var apis = [];
            for (var i = 0; i < elem.attributes.length; i++) {
                if (elem.attributes[i].name) {
                    var mc = elem.attributes[i].name.match(/url-(.*)/);
                    if (mc && mc[1]) {
                        apis.push({
                            key: mc[1],
                            url: elem.attributes[i].value
                        })
                    }
                }
            }
            var data = {};
            var render = function (resp) {
                var qkr_tmpl = elem.getAttribute("qkr-tmpl");

                if(qkr_tmpl){
                    if(compiled_temp[qkr_tmpl]){
                        elem.innerHTML  = compiled_temp[qkr_tmpl](resp);
                    }
                    return;
                } else if (!elem.getAttribute("qkr")) {
                    elem.innerHTML = quikr.tmpl(elem.id, resp);
                } else {
                    var children = elem.children;
                    var innerHTML = "";
                    if (children.length == 1 && children[0].nodeName == "SCRIPT") {
                        innerHTML = children[0].innerHTML;
                    } else {
                        innerHTML = elem.innerHTML;
                    }
                    var newTag = elem.getAttribute('tag');
                    var innerHTMLOut = quikr.tmpl(jQuery("<textarea/>").html(innerHTML).val(), resp, elem.id);
                    if (elem.nodeName === "SCRIPT" && newTag) {
                        elem.innerHTML = "";
                        var $elem = jQuery(elem.outerHTML.replace(/^<script/, "<" + newTag).replace(/<\/script>$/, "</" + newTag + ">"));
                        jQuery(elem).replaceWith($elem);

                        elem = $elem[0];
                        //console.error(innerHTMLOut)
                    }
                    elem.innerHTML = innerHTMLOut;
                }
                elem.setAttribute('qkr', "");
                jQuery(elem).removeAttr("qkr-attr").find("[qkr-attr]").removeAttr("qkr-attr");

            };

            if (apis.length > 0) {
                jQuery.when.apply($, apis.map(function (api) {
                    return quikr.get(api.url, elem.dataset).then(function (resp) {
                        data[api.key] = resp;
                        return data;
                    });
                })).done(function (resp) {
                    render(resp);
                });
            } else if (rawdata) {
                render(rawdata);
            } else {
                render(elem.dataset);
            }
        }
    };

    quikr.init = function () {
        jQuery('script[type="text/qkr-tmpl"]').each(function (i, elem) {
            compiled_temp[elem.id] = quikr.tmpl(elem.innerHTML, undefined ,elem.id);
        });
        jQuery('[qkr="tmpl"],[qkr-tmpl]').each(function (i, elem) {
            quikr.applyTmpl(elem);
        });
        jQuery("body").on("click", '[qkr-action]', function (e) {
            var elem = e.target;
            var action = elem.getAttribute("qkr-action");

            var getUrl = elem.getAttribute("get-url") || ((action=="qkr-get") ? elem.getAttribute("qkr-url") : null);
            var postUrl = elem.getAttribute("post-url") || ((action=="qkr-post") ? elem.getAttribute("qkr-url") : null);

            var callback = function (resp) {
                if (typeof quikr._actions_[action] === "function") {
                    quikr._actions_[action].call(elem, resp);
                }
            };
            var data = {};
            for (var key in elem.dataset) {
                if (elem.dataset[key].indexOf("?") == 0) {
                    data[key] = root.prompt(elem.dataset[key].substr(1) || key, "");
                } else {
                    data[key] = elem.dataset[key];
                }
            }
            if (getUrl) {
                jQuery.get(getUrl, data).done(callback);
            } else if (postUrl) {
                jQuery.post(postUrl, data).done(callback);
            } else {
                callback(data);
            }
        });
    };

    quikr.action("qkr-reload", function (data) {
        var tmpl = this.getAttribute("qkr-tmpl");
        quikr.applyTmpl(document.getElementById(tmpl));
    });

    function loadImage(el, options) {
        var status = el.getAttribute('quikr-status');
        var prop = "data-src";
        if (status == "loaded") {
            return;
        } else if (status == "error") {
            var srcs = [];
            for (var i = 0; i < el.attributes.length; i++) {
                if (/data-src-?[0-9]*/.test(el.attributes[i].name)) {
                    srcs.push(el.attributes[i].name)
                }
            }
            srcs = srcs.sort();
            if (!srcs.length) {
                // return;
            }
            prop = srcs.shift();
        }
        var img = el.img || new Image()
            , src = el.getAttribute(prop);
        el.removeAttribute(prop);
        if (!src) {
            //Contiune to Set Callbacks only
            // return;
        }
        if (options.blank && !el.src) {
            el.src = el.src || src;
        }

        img.onload = src ? function () {
            if (!!el.parent)
                el.parent.replaceChild(img, el)
            else if (src && status != "loaded") {
                el.src = src;
                el.setAttribute('quikr-status', 'loaded');
            }
        } : img.onload;

        if (!options["404"]) {
            //console.error("NO OPTIONS=",el, options);
        }
        img.onerror = img.onerror || function () {
                el.setAttribute('quikr-status', 'error');
                el.setAttribute('quikr-img-error', img.src);
                if (options["404"]) {
                    el.src = options["404"];
                } else {
                    //console.error("NO OPTIONS==",el, options);
                }
                loadImage(el, {404: options["404"], blank: options.blank});
            };
        var onerror = options.error || options;
        if (typeof onerror == "function") {
            var old_onerror = img.onerror;
            img.onerror = function () {
                old_onerror.apply(this, arguments);
                return onerror.apply(this, arguments);
            }
        }
        if (src) {
            img.src = src;
            el.setAttribute('quikr-status', 'loading');
            el.setAttribute('quikr-img-loading', img.src);
        } else if (img && typeof img.onerror == 'function') {
            //img.onerror(src);
            //WARNING : Triggers Infinite Loop
        }
        el.img = img;
    }

    function elementInViewport(el) {
        var rect = el.getBoundingClientRect()

        return (
            rect.top >= 0
            && rect.left >= 0
            && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
        )
    }

    jQuery.fn.loadLazyImages = function (options, _force) {
        var force = _force || true;
        this.each(function (i, elem) {
            if (force || elementInViewport(elem)) {
                loadImage(elem, options || {});
            }
        })
    };
    var loadLazyImages = function (options, _force) {
        if (options === true || options === false) {
            var __force = options;
            options = _force;
            _force = __force;
        }
        var force = _force || false;
        images = jQuery('img[data-src],img[quikr-status="error"]');
        for (var i = 0; i < images.length; i++) {
            if (force || elementInViewport(images[i])) {
                loadImage(images[i], options || {});
            }
        }
        ;
    };
    quikr.loadLazyImages = loadLazyImages;

    root.quikr = quikr;
})(this);
<commit_msg>tmpl fixed<commit_after>!(function (root) {

    var tmpl_cache = {};
    var compiled_temp = {};
    var resp_cache = {};
    var quikr = {
        cache_time: 5000,
        tmpl: function tmpl(str, data, option_id) {
            // Figure out if we're getting a template, or if we need to
            // load the template - and be sure to cache the result.
            var fn = !/\W/.test(str) ?
                tmpl_cache[str] = tmpl_cache[str] ||
                    this.tmpl(document.getElementById(str).innerHTML) :
                // Generate a reusable function that will serve as a template
                // generator (and which will be cached).
                new Function("obj",
                    "var p=[],print=function(){p.push.apply(p,arguments);};" +

                    // Introduce the data as local variables using with(){}
                    "with(obj){p.push('" +

                    // Convert the template into pure JavaScript
                    str
                        .replace(/[\r\t\n]/g, " ")
                        .split("<%").join("\t")
                        .replace(/((^|%>)[^\t]*)'/g, "$1\r")
                        .replace(/\t=(.*?)%>/g, "',$1,'")
                        .split("\t").join("');")
                        .split("%>").join("p.push('")
                        .split("\r").join("\\'")
                    + "');}return p.join('');");

            if (option_id) {
                tmpl_cache[option_id] = fn;
            }
            // Provide some basic currying to the user
            return data ? fn(data) : fn;
        },
        get: function (url, data) {
            if (typeof this._urls_[url] == "function") {
                var resp = this._urls_[url](data);
                if (typeof resp.done == "function") {
                    return resp;
                } else {
                    return jQuery.Deferred(function ($d) {
                        $d.resolve(resp);
                    }).promise();
                }
            } else {
                var cache_url = url + ((url.indexOf("?") > -1) ? "&" : "?") + jQuery.param(data);
                if (resp_cache[cache_url] && resp_cache[cache_url].timestamp > new Date().getTime()) {
                    return resp_cache[cache_url].$req
                }
                resp_cache[cache_url] = {
                    timestamp: new Date().getTime() + this.cache_time,
                    $req: jQuery.get(url, data)
                };
                return resp_cache[cache_url].$req;
            }
        },
        _actions_: {},
        action: function (action, callback) {
            this._actions_[action] = callback;
            return this;
        },
        _urls_: {},
        url: function (url, callback) {
            this._urls_[url] = callback;
            return this;
        },
        applyTmpl: function (elem, rawdata) {
            var url = elem.getAttribute("url");
            var apis = [];
            for (var i = 0; i < elem.attributes.length; i++) {
                if (elem.attributes[i].name) {
                    var mc = elem.attributes[i].name.match(/url-(.*)/);
                    if (mc && mc[1]) {
                        apis.push({
                            key: mc[1],
                            url: elem.attributes[i].value
                        })
                    }
                }
            }
            var data = {};
            var render = function (resp) {
                var qkr_tmpl = elem.getAttribute("qkr-tmpl");

                if(qkr_tmpl){
                    if(compiled_temp[qkr_tmpl]){
                        elem.innerHTML  = compiled_temp[qkr_tmpl](resp);
                    }
                    return;
                } else if (!elem.getAttribute("qkr") && elem.hasAttribute("qkr-tmpl-compiled")) {
                    elem.innerHTML = quikr.tmpl(elem.id, resp);
                } else {
                    var children = elem.children;
                    var innerHTML = "";
                    if (children.length == 1 && children[0].nodeName == "SCRIPT") {
                        innerHTML = children[0].innerHTML;
                    } else {
                        innerHTML = elem.innerHTML;
                    }
                    var newTag = elem.getAttribute('tag');
                    var innerHTMLOut = quikr.tmpl(jQuery("<textarea/>").html(innerHTML).val(), resp, elem.id);
                    if (elem.nodeName === "SCRIPT" && newTag) {
                        elem.innerHTML = "";
                        var $elem = jQuery(elem.outerHTML.replace(/^<script/, "<" + newTag).replace(/<\/script>$/, "</" + newTag + ">"));
                        jQuery(elem).replaceWith($elem);

                        elem = $elem[0];
                        //console.error(innerHTMLOut)
                    }
                    elem.innerHTML = innerHTMLOut;
                    elem.setAttribute("qkr-tmpl-compiled","")
                }
                elem.setAttribute('qkr', "");
                jQuery(elem).removeAttr("qkr-attr").find("[qkr-attr]").removeAttr("qkr-attr");

            };

            if (apis.length > 0) {
                jQuery.when.apply($, apis.map(function (api) {
                    return quikr.get(api.url, elem.dataset).then(function (resp) {
                        data[api.key] = resp;
                        return data;
                    });
                })).done(function (resp) {
                    render(resp);
                });
            } else if (rawdata) {
                render(rawdata);
            } else {
                render(elem.dataset);
            }
        }
    };

    quikr.init = function () {
        jQuery('script[type="text/qkr-tmpl"]').each(function (i, elem) {
            compiled_temp[elem.id] = quikr.tmpl(elem.innerHTML, undefined ,elem.id);
        });
        jQuery('[qkr="tmpl"],[qkr-tmpl]').each(function (i, elem) {
            quikr.applyTmpl(elem);
        });
        jQuery("body").on("click", '[qkr-action]', function (e) {
            var elem = e.target;
            var action = elem.getAttribute("qkr-action");

            var getUrl = elem.getAttribute("get-url") || ((action=="qkr-get") ? elem.getAttribute("qkr-url") : null);
            var postUrl = elem.getAttribute("post-url") || ((action=="qkr-post") ? elem.getAttribute("qkr-url") : null);

            var callback = function (resp) {
                if (typeof quikr._actions_[action] === "function") {
                    quikr._actions_[action].call(elem, resp);
                }
            };
            var data = {};
            for (var key in elem.dataset) {
                if (elem.dataset[key].indexOf("?") == 0) {
                    data[key] = root.prompt(elem.dataset[key].substr(1) || key, "");
                } else {
                    data[key] = elem.dataset[key];
                }
            }
            if (getUrl) {
                jQuery.get(getUrl, data).done(callback);
            } else if (postUrl) {
                jQuery.post(postUrl, data).done(callback);
            } else {
                callback(data);
            }
        });
    };

    quikr.action("qkr-reload", function (data) {
        var tmpl = this.getAttribute("qkr-tmpl");
        quikr.applyTmpl(document.getElementById(tmpl));
    });

    function loadImage(el, options) {
        var status = el.getAttribute('quikr-status');
        var prop = "data-src";
        if (status == "loaded") {
            return;
        } else if (status == "error") {
            var srcs = [];
            for (var i = 0; i < el.attributes.length; i++) {
                if (/data-src-?[0-9]*/.test(el.attributes[i].name)) {
                    srcs.push(el.attributes[i].name)
                }
            }
            srcs = srcs.sort();
            if (!srcs.length) {
                // return;
            }
            prop = srcs.shift();
        }
        var img = el.img || new Image()
            , src = el.getAttribute(prop);
        el.removeAttribute(prop);
        if (!src) {
            //Contiune to Set Callbacks only
            // return;
        }
        if (options.blank && !el.src) {
            el.src = el.src || src;
        }

        img.onload = src ? function () {
            if (!!el.parent)
                el.parent.replaceChild(img, el)
            else if (src && status != "loaded") {
                el.src = src;
                el.setAttribute('quikr-status', 'loaded');
            }
        } : img.onload;

        if (!options["404"]) {
            //console.error("NO OPTIONS=",el, options);
        }
        img.onerror = img.onerror || function () {
                el.setAttribute('quikr-status', 'error');
                el.setAttribute('quikr-img-error', img.src);
                if (options["404"]) {
                    el.src = options["404"];
                } else {
                    //console.error("NO OPTIONS==",el, options);
                }
                loadImage(el, {404: options["404"], blank: options.blank});
            };
        var onerror = options.error || options;
        if (typeof onerror == "function") {
            var old_onerror = img.onerror;
            img.onerror = function () {
                old_onerror.apply(this, arguments);
                return onerror.apply(this, arguments);
            }
        }
        if (src) {
            img.src = src;
            el.setAttribute('quikr-status', 'loading');
            el.setAttribute('quikr-img-loading', img.src);
        } else if (img && typeof img.onerror == 'function') {
            //img.onerror(src);
            //WARNING : Triggers Infinite Loop
        }
        el.img = img;
    }

    function elementInViewport(el) {
        var rect = el.getBoundingClientRect()

        return (
            rect.top >= 0
            && rect.left >= 0
            && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
        )
    }

    jQuery.fn.loadLazyImages = function (options, _force) {
        var force = _force || true;
        this.each(function (i, elem) {
            if (force || elementInViewport(elem)) {
                loadImage(elem, options || {});
            }
        })
    };
    var loadLazyImages = function (options, _force) {
        if (options === true || options === false) {
            var __force = options;
            options = _force;
            _force = __force;
        }
        var force = _force || false;
        images = jQuery('img[data-src],img[quikr-status="error"]');
        for (var i = 0; i < images.length; i++) {
            if (force || elementInViewport(images[i])) {
                loadImage(images[i], options || {});
            }
        }
        ;
    };
    quikr.loadLazyImages = loadLazyImages;

    root.quikr = quikr;
})(this);
<|endoftext|>


<commit_before>describe('cookies', function () {
    var _ = require('lodash'),
        testrun;

    before(function (done) {
        this.run({
            collection: {
                item: [{
                    event: [{
                        listen: 'test',
                        script: {
                            type: 'text/javascript',
                            exec: ['tests["working"] = postman.getResponseCookie("foo").value === "bar"']
                        }
                    }],
                    request: 'http://postman-echo.com/cookies/set?foo=bar'
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            type: 'text/javascript',
                            exec: ['tests["working"] = postman.getResponseCookie("foo").value === "bar"']
                        }
                    }],
                    request: 'http://postman-echo.com/cookies/get'
                }]
            }
        }, function (err, results) {
            testrun = results;
            done(err);
        });
    });

    it('must have run the test script successfully', function () {
        expect(testrun).be.ok();
        expect(testrun.test.calledTwice).be.ok();

        expect(testrun.test.getCall(0).args[0]).to.be(null);
        expect(_.find(testrun.test.getCall(0).args[2][0].result.cookies, {name: 'foo'})).to.have
            .property('value', 'bar');
        expect(_.get(testrun.test.getCall(0).args[2], '0.result.request.headers.reference.cookie.value')).to
            .match(/foo=bar;/);

        expect(testrun.test.getCall(1).args[0]).to.be(null);
        expect(_.find(testrun.test.getCall(1).args[2][0].result.cookies, {name: 'foo'})).to.have
            .property('value', 'bar');
        expect(_.get(testrun.test.getCall(1).args[2], '0.result.request.headers.reference.cookie.value')).to
            .match(/foo=bar;/);
    });

    it('must have completed the run', function () {
        expect(testrun).be.ok();
        expect(testrun.done.calledOnce).be.ok();
        expect(testrun.done.getCall(0).args[0]).to.be(null);
        expect(testrun.start.calledOnce).be.ok();
    });
});
<commit_msg>Update integration/sanity/cookie-handling tests to chai<commit_after>var expect = require('chai').expect;

describe('cookies', function () {
    var _ = require('lodash'),
        testrun;

    before(function (done) {
        this.run({
            collection: {
                item: [{
                    event: [{
                        listen: 'test',
                        script: {
                            type: 'text/javascript',
                            exec: ['tests["working"] = postman.getResponseCookie("foo").value === "bar"']
                        }
                    }],
                    request: 'http://postman-echo.com/cookies/set?foo=bar'
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            type: 'text/javascript',
                            exec: ['tests["working"] = postman.getResponseCookie("foo").value === "bar"']
                        }
                    }],
                    request: 'http://postman-echo.com/cookies/get'
                }]
            }
        }, function (err, results) {
            testrun = results;
            done(err);
        });
    });

    it('should have run the test script successfully', function () {
        expect(testrun).to.be.ok;
        expect(testrun).to.nested.include({
            'test.calledTwice': true
        });

        expect(testrun.test.getCall(0).args[0]).to.be.null;
        expect(_.find(testrun.test.getCall(0).args[2][0].result.cookies, {name: 'foo'})).to.have
            .property('value', 'bar');
        expect(_.get(testrun.test.getCall(0).args[2], '0.result.request.headers.reference.cookie.value')).to
            .match(/foo=bar;/);

        expect(testrun.test.getCall(1).args[0]).to.be.null;
        expect(_.find(testrun.test.getCall(1).args[2][0].result.cookies, {name: 'foo'})).to.have
            .property('value', 'bar');
        expect(_.get(testrun.test.getCall(1).args[2], '0.result.request.headers.reference.cookie.value')).to
            .match(/foo=bar;/);
    });

    it('should have completed the run', function () {
        expect(testrun).to.be.ok;
        expect(testrun.done.getCall(0).args[0]).to.be.null;
        expect(testrun).to.nested.include({
            'done.calledOnce': true,
            'start.calledOnce': true
        });
    });
});
<|endoftext|>


<commit_before>/*
 * Chrome-Last.fm-Scrobbler for Daytrotter.com "new interface" Connector
 *
 * Tom Krall - tomkrall[at]gmail[dot]com
 *
 */

console.log('Entered daytrotter.js');

var track;
var artist;
var duration;
var current;

var _flg_Reported;

var container_duration = 'div#jp_interface_1.jp-interface div.jp-duration';
var container_currenttime = 'div#jp_interface_1.jp-interface div.jp-current-time';
var container_mediainfo	= 'div#jp_playlist_1.jp-playlist.single ul.nof li a';
var container_playbutton = 'a.jp-play';		//'div#jp_playlist_1.jp-playlist.single ul.nof.jp-controls li a.jp-pause';
var container_pausebutton = 'a.jp-pause';	//'div#jp_playlist_1.jp-playlist.single ul.nof.jp-controls li a.jp-play';

var _flg_IsPlaying = false;
var _flg_IsPaused = false;
var _flg_NeedsToBeReported = 0;
var _flg_HasBeenReported = 0;

function IsPaused(){
	return !_flg_IsPaused;
}

$(function(){

	console.log("Daytrotter module starting up");

	/*********************************************************************************************************************************

		Monitor the duration container for changes to the track. When the duration changes and is set, it is definitely a new track.

	**********************************************************************************************************************************/
	$(container_duration).live('DOMSubtreeModified', function(e) {

		var tempStr = $(container_mediainfo).text();
		var tempSplit = tempStr.split(" - ", 2);
		var t_artist = tempSplit[0];
		var t_track = tempSplit[1];
		var t_duration = $(container_duration).text();
		var t_current = $(container_currenttime).text();

		if (t_duration != duration && t_duration != "00:00" && t_duration != "" && (t_artist != artist || t_track != track))
		{
			if (track != t_track || artist != t_artist)
			{
				//console.log ("Polling Temp Track Info - PLAYING[%s] - DISPLAY[%s] - ARTIST[%s] - TRACK[%s] - CURRENT[%s] - DURATION[%s]",
				//			!IsPaused(), tempStr, t_artist, t_track, t_current, t_duration);

				artist = t_artist;
				track = t_track;
				duration = t_duration;

				if ( !IsPaused() )
				{
					console.log("posting track info");

					chrome.runtime.sendMessage({type: 'validate', artist: artist, track: track}, function(response) {
						if (response != false) {
							chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: track, duration: duration});
						} else { // on failure send nowPlaying 'unknown song'
							chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration});
						}
					});
				}
			}
		}
	});

	/*********************************************************************************************************************************

		Monitor the pause button to keep track of the "pause" status. It is shown while the play button is hidden. (track is playing)

	**********************************************************************************************************************************/

	var pauseElement = $(container_pausebutton).get(0);

	var pauseObserver = new WebKitMutationObserver(function (mutations) {
		mutations.forEach(attrModified);
	});

	var pauseConfig = { attributes: true, childList: false, characterData: false };
	pauseObserver.observe(pauseElement, pauseConfig);

	function attrModified(mutation) {
	 	var name = mutation.attributeName,
	    newValue = mutation.target.getAttribute(name),
	    oldValue = mutation.oldValue;

		if (name == "style"  &&  newValue == "display: none;")
		{
			console.log("pause button hidden");
			_flg_IsPaused = false;
		}
		else
		{
			console.log("pause button visibile (should be)");
			_flg_IsPaused = true;
		}
	}

	/*********************************************************************************************************************************

		Unload

	**********************************************************************************************************************************/
	$(window).unload(function() {
		console.log('unload');

		chrome.runtime.sendMessage({type: 'reset'});
		return true;
	});
});
<commit_msg>Update daytrotter.js<commit_after>/*
 * Chrome-Last.fm-Scrobbler for Daytrotter.com "new interface" Connector
 *
 * Tom Krall - tomkrall[at]gmail[dot]com
 *
 */

console.log('Entered daytrotter.js');

var mediainfo;
var track;
var artist;
var duration;
var current;

var _flg_Reported;

var container_duration = 'div#jp_interface_1.jp-interface div.jp-duration';
var container_currenttime = 'div#jp_interface_1.jp-interface div.jp-current-time';
var container_mediainfo	= 'div#jp_playlist_1.jp-playlist.single ul.nof li a';
var container_playbutton = 'a.jp-play';		//'div#jp_playlist_1.jp-playlist.single ul.nof.jp-controls li a.jp-pause';
var container_pausebutton = 'a.jp-pause';	//'div#jp_playlist_1.jp-playlist.single ul.nof.jp-controls li a.jp-play';

var _flg_IsPlaying = false;
var _flg_IsPaused = false;
var _flg_NeedsToBeReported = 0;
var _flg_HasBeenReported = 0;

function IsPaused(){
	return !_flg_IsPaused;
}

$(function(){

	console.log("Daytrotter module starting up");

	/*********************************************************************************************************************************

		Monitor the duration container for changes to the track. When the duration changes and is set, it is definitely a new track.

	**********************************************************************************************************************************/
	$(container_duration).live('DOMSubtreeModified', function(e) {

		var t_mediainfo = $(container_mediainfo).text();
		var tempSplit = t_mediainfo.split(" - ", 2);
		var t_artist = tempSplit[0];
		var t_track = tempSplit[1];
		var t_duration = $(container_duration).text();
		var t_current = $(container_currenttime).text();

		if (t_duration != duration && t_duration != "00:00" && t_duration != "" && (t_artist != artist || t_track != track))
		{
			if (track != t_track || artist != t_artist)
			{
				//console.log ("Polling Temp Track Info - PLAYING[%s] - DISPLAY[%s] - ARTIST[%s] - TRACK[%s] - CURRENT[%s] - DURATION[%s]",
				//			!IsPaused(), t_mediainfo, t_artist, t_track, t_current, t_duration);

				mediainfo = t_mediainfo;
				artist = t_artist;
				track = t_track;
				duration = t_duration;

				if ( !IsPaused() )
				{
					//console.log("posting track info");

					chrome.runtime.sendMessage({type: 'validate', artist: artist, track: track}, function(response) {
						if (response != false) {
							chrome.runtime.sendMessage({type: 'nowPlaying', artist: artist, track: track, duration: duration});
						} else { // on failure send nowPlaying 'unknown song'

							//if validation failed, consider trying to determine if it is from an "official" playlist and parsing out the media info again to validate.
							//
							//	To be done later
							//

							chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration});
						}
					});
				}
			}
		}
	});

	/*********************************************************************************************************************************

		Monitor the pause button to keep track of the "pause" status. It is shown while the play button is hidden. (track is playing)

	**********************************************************************************************************************************/

	var pauseElement = $(container_pausebutton).get(0);

	var pauseObserver = new WebKitMutationObserver(function (mutations) {
		mutations.forEach(attrModified);
	});

	var pauseConfig = { attributes: true, childList: false, characterData: false };
	pauseObserver.observe(pauseElement, pauseConfig);

	function attrModified(mutation) {
	 	var name = mutation.attributeName,
	    newValue = mutation.target.getAttribute(name),
	    oldValue = mutation.oldValue;

		if (name == "style"  &&  newValue == "display: none;")
		{
			//console.log("pause button hidden");
			_flg_IsPaused = false;
		}
		else
		{
			//console.log("pause button visibile (should be)");
			_flg_IsPaused = true;
		}
	}

	/*********************************************************************************************************************************

		Unload

	**********************************************************************************************************************************/
	$(window).unload(function() {
		console.log('unload');

		chrome.runtime.sendMessage({type: 'reset'});
		return true;
	});
});
<|endoftext|>


<commit_before>'use strict';

var React   = require('react-native');
var Button  = require('react-native-button');
var Modal   = require('react-native-modalbox');
var Slider  = require('react-native-slider');
var window  = require('Dimensions').get('window');

var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ScrollView
} = React;

var styles = StyleSheet.create({

  wrapper: {
    paddingTop: 50,
    flex: 1
  },

  modal: {
    justifyContent: 'center',
    alignItems: 'center'
  },

  modal2: {
    height: 230,
    backgroundColor: "#3B5998"
  },

  modal3: {
    height: 300,
    width: 300
  },

  modal4: {
    height: 300
  },

  btn: {
    margin: 10,
    backgroundColor: "#3B5998",
    color: "white",
    padding: 10
  },

  btnModal: {
    position: "absolute",
    top: 0,
    right: 0,
    width: 50,
    height: 50,
    backgroundColor: "transparent"
  },

  text: {
    color: "black",
    fontSize: 22
  }

});

var Example = React.createClass({

  getInitialState: function() {
    return {
      isOpen: false,
      isDisabled: false,
      swipeToClose: true,
      sliderValue: 0.3
    };
  },

  openModal1: function(id) {
    this.refs.modal1.open();
  },

  openModal2: function(id) {
    this.refs.modal2.open();
  },

  openModal3: function(id) {
    this.refs.modal3.open();
  },

  openModal4: function(id) {
    this.refs.modal4.open();
  },

  openModal5: function(id) {
    this.setState({isOpen: true});
  },

  closeModal5: function(id) {
    this.setState({isOpen: false});
  },

  openModal6: function(id) {
    this.refs.modal6.open();
  },

  openModal6: function(id) {
    this.refs.modal6.open();
  },

  toggleDisable: function() {
    this.setState({isDisabled: !this.state.isDisabled});
  },

  toggleSwipeToClose: function() {
    this.setState({swipeToClose: !this.state.swipeToClose});
  },

  onClose: function() {
    console.log('Modal just closed');
  },

  onOpen: function() {
    console.log('Modal just openned');
  },

  onClosingState: function(state) {
    console.log('the open/close of the swipeToClose just changed');
  },

  renderList() {
    var list = [];

    for (var i=0;i<50;i++) {
      list.push(<Text style={styles.text} key={i}>Elem {i}</Text>);
    }

    return list;
  },

  render: function() {

    var BContent = <Button onPress={this.closeModal5} style={[styles.btn, styles.btnModal]}>X</Button>;

    return (
      <View style={styles.wrapper}>
        <Button onPress={this.openModal1} style={styles.btn}>Basic modal</Button>
        <Button onPress={this.openModal2} style={styles.btn}>Position top</Button>
        <Button onPress={this.openModal3} style={styles.btn}>Position centered + backdrop + disable</Button>
        <Button onPress={this.openModal4} style={styles.btn}>Position bottom + backdrop + slider</Button>
        <Button onPress={this.openModal5} style={styles.btn}>Backdrop + backdropContent</Button>
        <Button onPress={this.openModal6} style={styles.btn}>Position bottom + ScrollView</Button>

        <Modal style={[styles.modal, styles.modal1]} ref={"modal1"} swipeToClose={this.state.swipeToClose} onClosed={this.onClose} onOpened={this.onOpen} onClosingState={this.onClosingState}>
          <Text style={styles.text}>Basic modal</Text>
          <Button onPress={this.toggleSwipeToClose} style={styles.btn}>Disable swipeToClose({this.state.swipeToClose ? "true" : "false"})</Button>
        </Modal>

        <Modal style={[styles.modal, styles.modal2]} backdrop={false}  position={"top"} ref={"modal2"}>
          <Text style={[styles.text, {color: "white"}]}>Modal on top</Text>
        </Modal>

        <Modal style={[styles.modal, styles.modal3]} position={"center"} ref={"modal3"} isDisabled={this.state.isDisabled}>
          <Text style={styles.text}>Modal centered</Text>
          <Button onPress={this.toggleDisable} style={styles.btn}>Disable ({this.state.isDisabled ? "true" : "false"})</Button>
        </Modal>

        <Modal style={[styles.modal, styles.modal4]} position={"bottom"} ref={"modal4"}>
          <Text style={styles.text}>Modal on bottom with backdrop</Text>
          <Slider style={{width: 200}} value={this.state.sliderValue} onValueChange={(value) => this.setState({sliderValue: value})} />
        </Modal>

        <Modal isOpen={this.state.isOpen} onClosed={this.closeModal5} style={[styles.modal, styles.modal4]} position={"center"} backdropContent={BContent}>
          <Text style={styles.text}>Modal with backdrop content</Text>
        </Modal>

        <Modal style={[styles.modal, styles.modal4]} position={"bottom"} ref={"modal6"} swipeArea={20}>
          <ScrollView>
            <View style={{width: window.width, paddingLeft: 10}}>
              {this.renderList()}
            </View>
          </ScrollView>
        </Modal>
      </View>
    );
  }
});

AppRegistry.registerComponent('Example', () => Example);
<commit_msg>Changes to example, compatible with RN 0.25<commit_after>'use strict';

var React   = require('react');
var Button  = require('react-native-button');
var Modal   = require('react-native-modalbox');
var Slider  = require('react-native-slider');
var window  = require('Dimensions').get('window');

var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ScrollView
} = require('react-native');

var styles = StyleSheet.create({

  wrapper: {
    paddingTop: 50,
    flex: 1
  },

  modal: {
    justifyContent: 'center',
    alignItems: 'center'
  },

  modal2: {
    height: 230,
    backgroundColor: "#3B5998"
  },

  modal3: {
    height: 300,
    width: 300
  },

  modal4: {
    height: 300
  },

  btn: {
    margin: 10,
    backgroundColor: "#3B5998",
    color: "white",
    padding: 10
  },

  btnModal: {
    position: "absolute",
    top: 0,
    right: 0,
    width: 50,
    height: 50,
    backgroundColor: "transparent"
  },

  text: {
    color: "black",
    fontSize: 22
  }

});

var Example = React.createClass({

  getInitialState: function() {
    return {
      isOpen: false,
      isDisabled: false,
      swipeToClose: true,
      sliderValue: 0.3
    };
  },

  openModal1: function(id) {
    this.refs.modal1.open();
  },

  openModal2: function(id) {
    this.refs.modal2.open();
  },

  openModal3: function(id) {
    this.refs.modal3.open();
  },

  openModal4: function(id) {
    this.refs.modal4.open();
  },

  openModal5: function(id) {
    this.setState({isOpen: true});
  },

  closeModal5: function(id) {
    this.setState({isOpen: false});
  },

  openModal6: function(id) {
    this.refs.modal6.open();
  },

  openModal6: function(id) {
    this.refs.modal6.open();
  },

  toggleDisable: function() {
    this.setState({isDisabled: !this.state.isDisabled});
  },

  toggleSwipeToClose: function() {
    this.setState({swipeToClose: !this.state.swipeToClose});
  },

  onClose: function() {
    console.log('Modal just closed');
  },

  onOpen: function() {
    console.log('Modal just openned');
  },

  onClosingState: function(state) {
    console.log('the open/close of the swipeToClose just changed');
  },

  renderList() {
    var list = [];

    for (var i=0;i<50;i++) {
      list.push(<Text style={styles.text} key={i}>Elem {i}</Text>);
    }

    return list;
  },

  render: function() {

    var BContent = <Button onPress={this.closeModal5} style={[styles.btn, styles.btnModal]}>X</Button>;

    return (
      <View style={styles.wrapper}>
        <Button onPress={this.openModal1} style={styles.btn}>Basic modal</Button>
        <Button onPress={this.openModal2} style={styles.btn}>Position top</Button>
        <Button onPress={this.openModal3} style={styles.btn}>Position centered + backdrop + disable</Button>
        <Button onPress={this.openModal4} style={styles.btn}>Position bottom + backdrop + slider</Button>
        <Button onPress={this.openModal5} style={styles.btn}>Backdrop + backdropContent</Button>
        <Button onPress={this.openModal6} style={styles.btn}>Position bottom + ScrollView</Button>

        <Modal style={[styles.modal, styles.modal1]} ref={"modal1"} swipeToClose={this.state.swipeToClose} onClosed={this.onClose} onOpened={this.onOpen} onClosingState={this.onClosingState}>
          <Text style={styles.text}>Basic modal</Text>
          <Button onPress={this.toggleSwipeToClose} style={styles.btn}>Disable swipeToClose({this.state.swipeToClose ? "true" : "false"})</Button>
        </Modal>

        <Modal style={[styles.modal, styles.modal2]} backdrop={false}  position={"top"} ref={"modal2"}>
          <Text style={[styles.text, {color: "white"}]}>Modal on top</Text>
        </Modal>

        <Modal style={[styles.modal, styles.modal3]} position={"center"} ref={"modal3"} isDisabled={this.state.isDisabled}>
          <Text style={styles.text}>Modal centered</Text>
          <Button onPress={this.toggleDisable} style={styles.btn}>Disable ({this.state.isDisabled ? "true" : "false"})</Button>
        </Modal>

        <Modal style={[styles.modal, styles.modal4]} position={"bottom"} ref={"modal4"}>
          <Text style={styles.text}>Modal on bottom with backdrop</Text>
          <Slider style={{width: 200}} value={this.state.sliderValue} onValueChange={(value) => this.setState({sliderValue: value})} />
        </Modal>

        <Modal isOpen={this.state.isOpen} onClosed={this.closeModal5} style={[styles.modal, styles.modal4]} position={"center"} backdropContent={BContent}>
          <Text style={styles.text}>Modal with backdrop content</Text>
        </Modal>

        <Modal style={[styles.modal, styles.modal4]} position={"bottom"} ref={"modal6"} swipeArea={20}>
          <ScrollView>
            <View style={{width: window.width, paddingLeft: 10}}>
              {this.renderList()}
            </View>
          </ScrollView>
        </Modal>
      </View>
    );
  }
});

AppRegistry.registerComponent('Example', () => Example);
<|endoftext|>


<commit_before>'use strict';

window.SC_ATTACHED = window.SC_ATTACHED || false;

let currentState = {};
/**
 * Flag indicates now playing track is private.
 * The extension does not scrobble such tracks.
 * @type {Boolean}
 */
let isPrivate = false;

const progressSelector = '.playControls div[role=progressbar]';
const playButtonSelector = '.playControls button.playControl';

/**
 * Regular expression used to split artist and track.
 * There're two different hyphen chars in the regexp.
 * Codes are 0x2d and 0x2013.
 * @type {RegExp}
 */
const artistTrackRe = /(.+)\s?[-–—:]\s?(.+)/;

Connector.playerSelector = '.playControls';

Connector.getCurrentState = () => {
	currentState.currentTime = getCurrentTime();
	currentState.isPlaying = isPlaying();
	return currentState;
};

Connector.isScrobblingAllowed = () => !isPrivate;

Connector.filter = MetadataFilter.getYoutubeFilter();

function getCurrentTime() {
	return parseFloat($(progressSelector).attr('aria-valuenow')) / 1000;
}

function isPlaying() {
	return $(playButtonSelector).hasClass('playing');
}

/**
 * Parse metadata and set local letiables
 * @param {Object} metadata Data received from script injected in DOM
 */
function setSongData(metadata) {
	isPrivate = metadata.sharing === 'private';

	if (isPrivate) {
		currentState = {};
		return;
	}

	// Sometimes the artist name is in the track title,
	// e.g. Tokyo Rose - Zender Overdrive by Aphasia Records.
	let match = artistTrackRe.exec(metadata.title);

	// But don't interpret patterns of the form
	// "[Start of title] #1234 - [End of title]" as Artist - Title
	if (match && ! /.*#\d+.*/.test(match[1])) {
		currentState.artist = match[1];
		currentState.track = match[2];
	} else {
		currentState.artist = metadata.user.username;
		currentState.track = metadata.title;
	}

	currentState.duration = Math.floor(metadata.duration / 1000);
	// Use permalink url as the unique id
	currentState.uniqueID = metadata.permalink_url;
	currentState.trackArt = metadata.artwork_url;
}

/**
 * Run at initialisation; add dom script and attach events.
 */
(function() {
	// Exit if already attached.
	if (window.SC_ATTACHED) {
		return;
	}

	// Inject script to extract events from the Soundcloud API event-bus.
	// FIXME: Replace to `chrome.runtime.getURL`.
	let scriptUrl = chrome.extension.getURL('connectors/soundcloud-dom-inject.js');
	Util.injectScriptIntoDocument(scriptUrl);

	// Trigger functions based on message type.
	function eventHandler(e) {
		switch (e.data.type) {
			case 'SC_PLAY':
				setSongData(e.data.metadata);
				break;
			default:
				break;
		}
	}

	// Attach listener for message events.
	window.addEventListener('message', eventHandler);
	window.SC_ATTACHED = true;
}());
<commit_msg>Update code comment<commit_after>'use strict';

window.SC_ATTACHED = window.SC_ATTACHED || false;

let currentState = {};
/**
 * Flag indicates now playing track is private.
 * The extension does not scrobble such tracks.
 * @type {Boolean}
 */
let isPrivate = false;

const progressSelector = '.playControls div[role=progressbar]';
const playButtonSelector = '.playControls button.playControl';

/**
 * Regular expression used to split artist and track.
 * There're three different '-' chars in the regexp:
 * hyphen (0x2d), en dash (0x2013), em dash (0x2014).
 * @type {RegExp}
 */
const artistTrackRe = /(.+)\s?[-–—:]\s?(.+)/;

Connector.playerSelector = '.playControls';

Connector.getCurrentState = () => {
	currentState.currentTime = getCurrentTime();
	currentState.isPlaying = isPlaying();
	return currentState;
};

Connector.isScrobblingAllowed = () => !isPrivate;

Connector.filter = MetadataFilter.getYoutubeFilter();

function getCurrentTime() {
	return parseFloat($(progressSelector).attr('aria-valuenow')) / 1000;
}

function isPlaying() {
	return $(playButtonSelector).hasClass('playing');
}

/**
 * Parse metadata and set local letiables
 * @param {Object} metadata Data received from script injected in DOM
 */
function setSongData(metadata) {
	isPrivate = metadata.sharing === 'private';

	if (isPrivate) {
		currentState = {};
		return;
	}

	// Sometimes the artist name is in the track title,
	// e.g. Tokyo Rose - Zender Overdrive by Aphasia Records.
	let match = artistTrackRe.exec(metadata.title);

	// But don't interpret patterns of the form
	// "[Start of title] #1234 - [End of title]" as Artist - Title
	if (match && ! /.*#\d+.*/.test(match[1])) {
		currentState.artist = match[1];
		currentState.track = match[2];
	} else {
		currentState.artist = metadata.user.username;
		currentState.track = metadata.title;
	}

	currentState.duration = Math.floor(metadata.duration / 1000);
	// Use permalink url as the unique id
	currentState.uniqueID = metadata.permalink_url;
	currentState.trackArt = metadata.artwork_url;
}

/**
 * Run at initialisation; add dom script and attach events.
 */
(function() {
	// Exit if already attached.
	if (window.SC_ATTACHED) {
		return;
	}

	// Inject script to extract events from the Soundcloud API event-bus.
	// FIXME: Replace to `chrome.runtime.getURL`.
	let scriptUrl = chrome.extension.getURL('connectors/soundcloud-dom-inject.js');
	Util.injectScriptIntoDocument(scriptUrl);

	// Trigger functions based on message type.
	function eventHandler(e) {
		switch (e.data.type) {
			case 'SC_PLAY':
				setSongData(e.data.metadata);
				break;
			default:
				break;
		}
	}

	// Attach listener for message events.
	window.addEventListener('message', eventHandler);
	window.SC_ATTACHED = true;
}());
<|endoftext|>


<commit_before>import Config from './infra/config'
import { sign } from './infra/jwt'
import request from 'request-promise'

const apiClient = request.defaults({ baseUrl: Config.get('proxy.url') })

export function findOrCreateUserByProfile(profile) {

    const anonymousJwt = sign({ anonymous: true }, '5s')

    const options = {
        json: profile,
        headers: {
            Authorization: `Bearer ${anonymousJwt}`,
        },
    }

    return apiClient.post('/api/users/me', options).then((result) => {
        return sign({
            id: result.id,
            name: profile.name,
            avatarUrl: profile.avatarUrl,
            isAnonymous: result.isAnonymous,
        })
    })
}
<commit_msg>fix: correctly name the apiUrl variable name<commit_after>import Config from './infra/config'
import { sign } from './infra/jwt'
import request from 'request-promise'

const apiClient = request.defaults({ baseUrl: Config.get('proxy.apiUrl') })

export function findOrCreateUserByProfile(profile) {

    const anonymousJwt = sign({ anonymous: true }, '5s')

    const options = {
        json: profile,
        headers: {
            Authorization: `Bearer ${anonymousJwt}`,
        },
    }

    return apiClient.post('/api/users/me', options).then((result) => {
        return sign({
            id: result.id,
            name: profile.name,
            avatarUrl: profile.avatarUrl,
            isAnonymous: result.isAnonymous,
        })
    })
}
<|endoftext|>


<commit_before>/*globals WebGMEGlobal*/
/*jshint node:true, mocha:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */

var testFixture = require('../../_globals.js');

describe('ExecutorClient', function () {
    'use strict';

    var rimraf = testFixture.rimraf,
        should = testFixture.should,
        ExecutorClient = testFixture.ExecutorClient,
        executorClient,
        server;

    before(function (done) {
        // we have to set the config here
        var gmeConfig = testFixture.getGmeConfig(),
            param = {};

        gmeConfig.server.port = 9006;
        gmeConfig.executor.enable = true;

        param.serverPort = gmeConfig.server.port;
        param.httpsecure = gmeConfig.server.https.enable;

        rimraf('./test-tmp/executor', function (err) {
            if (err) {
                done(err);
                return;
            }
            server = testFixture.WebGME.standaloneServer(gmeConfig);
            server.start(function () {
                executorClient = new ExecutorClient(param);
                done();
            });
        });
    });

    after(function (done) {
        server.stop(function (err) {
            done(err);
        });
    });

    it('getWorkersInfo should return empty object', function (done) {
        executorClient.getWorkersInfo(function (err, res) {
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            should.equal(Object.keys(res).length, 0);
            done();
        });
    });

    it('createJob followed by getInfo should return CREATED jobInfo', function (done) {
        var jobInfo = {
            hash: '77704f10a36aa4214f5b0095ba8099e729a10f46'
        };
        executorClient.createJob(jobInfo, function (err, res) {
            var createTime;
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            createTime = res.createTime;
            should.equal(res.status, 'CREATED');
            should.equal(typeof createTime, 'string');
            executorClient.getInfo(jobInfo.hash, function (err, res) {
                if (err) {
                    done(err);
                    return;
                }
                should.equal(typeof res, 'object');
                should.equal(res.createTime, createTime);
                should.equal(res.status, 'CREATED');
                jobInfo.status = 'FAILED';
                executorClient.updateJob(jobInfo, function (err) {
                    if (err) {
                        done(err);
                    }
                    done();
                });
            });
        });
    });

    it('getInfo for non-existing hash should return 404', function (done) {
        executorClient.getInfo('87704f10a36aa4214f5b0095ba8099e729a10f46', function (err/*, res*/) {
            should.equal(err, 404);
            done();
        });
    });

    it('getAllInfo should return 500', function (done) {
        executorClient.getAllInfo(function (err) {
            should.equal(err, 500);
            done();
        });
    });

    it('updateJob with SUCCESS followed by getInfo should return SUCCESS in jobInfo', function (done) {
        var jobInfo = {
            hash: '88804f10a36aa4214f5b0095ba8099e729a10f46'
        };
        executorClient.createJob(jobInfo, function (err, res) {
            var createTime;
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            createTime = res.createTime;
            should.equal(res.status, 'CREATED');
            should.equal(typeof createTime, 'string');
            jobInfo.status = 'SUCCESS';
            executorClient.updateJob(jobInfo, function (err) {
                if (err) {
                    done(err);
                }
                executorClient.getInfo(jobInfo.hash, function (err, res) {
                    if (err) {
                        done(err);
                        return;
                    }
                    should.equal(typeof res, 'object');
                    should.equal(res.createTime, createTime);
                    should.equal(res.status, 'SUCCESS');
                    done();
                });
            });
        });
    });

});<commit_msg>#205 add 2 tests for ExecutorClient<commit_after>/*globals WebGMEGlobal*/
/*jshint node:true, mocha:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */

var testFixture = require('../../_globals.js');

describe('ExecutorClient', function () {
    'use strict';

    var rimraf = testFixture.rimraf,
        should = testFixture.should,
        expect = testFixture.expect,
        ExecutorClient = testFixture.ExecutorClient,
        executorClient,
        server;

    before(function (done) {
        // we have to set the config here
        var gmeConfig = testFixture.getGmeConfig(),
            param = {};

        gmeConfig.server.port = 9006;
        gmeConfig.executor.enable = true;

        param.serverPort = gmeConfig.server.port;
        param.httpsecure = gmeConfig.server.https.enable;

        rimraf('./test-tmp/executor', function (err) {
            if (err) {
                done(err);
                return;
            }
            server = testFixture.WebGME.standaloneServer(gmeConfig);
            server.start(function () {
                executorClient = new ExecutorClient(param);
                done();
            });
        });
    });

    after(function (done) {
        server.stop(function (err) {
            done(err);
        });
    });

    it('should get create url', function () {
        expect(typeof executorClient.getCreateURL === 'function').to.equal(true);
        expect(executorClient.getCreateURL()).to.contain('create');
        expect(executorClient.getCreateURL('1234567890abcdef')).to.contain('1234567890abcdef');
    });

    it('getWorkersInfo should return empty object', function (done) {
        executorClient.getWorkersInfo(function (err, res) {
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            should.equal(Object.keys(res).length, 0);
            done();
        });
    });

    it('createJob followed by getInfo should return CREATED jobInfo', function (done) {
        var jobInfo = {
            hash: '77704f10a36aa4214f5b0095ba8099e729a10f46'
        };
        executorClient.createJob(jobInfo, function (err, res) {
            var createTime;
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            createTime = res.createTime;
            should.equal(res.status, 'CREATED');
            should.equal(typeof createTime, 'string');
            executorClient.getInfo(jobInfo.hash, function (err, res) {
                if (err) {
                    done(err);
                    return;
                }
                should.equal(typeof res, 'object');
                should.equal(res.createTime, createTime);
                should.equal(res.status, 'CREATED');
                jobInfo.status = 'FAILED';
                executorClient.updateJob(jobInfo, function (err) {
                    if (err) {
                        done(err);
                    }
                    done();
                });
            });
        });
    });

    it('getInfo for non-existing hash should return 404', function (done) {
        executorClient.getInfo('87704f10a36aa4214f5b0095ba8099e729a10f46', function (err/*, res*/) {
            should.equal(err, 404);
            done();
        });
    });

    it('should get info by status', function (done) {
        executorClient.getInfoByStatus('CREATED', function (err/*, res*/) {
            should.equal(err, 500);
            done();
        });
    });

    it('getAllInfo should return 500', function (done) {
        executorClient.getAllInfo(function (err) {
            should.equal(err, 500);
            done();
        });
    });

    it('updateJob with SUCCESS followed by getInfo should return SUCCESS in jobInfo', function (done) {
        var jobInfo = {
            hash: '88804f10a36aa4214f5b0095ba8099e729a10f46'
        };
        executorClient.createJob(jobInfo, function (err, res) {
            var createTime;
            if (err) {
                done(err);
                return;
            }
            should.equal(typeof res, 'object');
            createTime = res.createTime;
            should.equal(res.status, 'CREATED');
            should.equal(typeof createTime, 'string');
            jobInfo.status = 'SUCCESS';
            executorClient.updateJob(jobInfo, function (err) {
                if (err) {
                    done(err);
                }
                executorClient.getInfo(jobInfo.hash, function (err, res) {
                    if (err) {
                        done(err);
                        return;
                    }
                    should.equal(typeof res, 'object');
                    should.equal(res.createTime, createTime);
                    should.equal(res.status, 'SUCCESS');
                    done();
                });
            });
        });
    });
});<|endoftext|>