<commit_before>var isObject = require("lodash/lang/isObject");
var flatten = require("lodash/array/flatten");
var fs = require("fs");
var path = require("path");
var jsbeautify = require("js-beautify");
var esprima = require("esprima");
var es = require("./es");
var ast = require("./ast");

// TODO: Statically analyze use of undeclared variables.
// TODO: Freeze functions also.

function transformAst(node) {
    if (!isObject(node)) {
        throw new Error("Not a node: " + jsonify(node));
    }
    if (handlers.hasOwnProperty(node.type)) {
        return handlers[node.type](node);
    }
    throw new Error("Unknown AST node: " + jsonify(node));
}

function jsonify(x) {
    return JSON.stringify(x);
}

function literal(node) {
    return es.Literal(node.data);
}

var PREDEF = require("./predef-ast");

function moduleExportsEq(x) {
    return es.ExpressionStatement(
        es.AssignmentExpression('=',
            es.MemberExpression(false,
                es.Identifier('module'),
                es.Identifier('exports')
            ),
            x
        )
    );
}

function cleanIdentifier(s) {
    if (/^if|else|while|do$/.test(s)) {
        return '$' + s;
    }
    return s
        .replace(/\+/g, '$plus')
        .replace(/-/g, '$minus')
        .replace(/\*/g, '$star')
        .replace(/\//g, '$slash')
        .replace(/!/g, '$bang')
        .replace(/;/g, '$semicolon')
        .replace(/@/g, '$at')
        .replace(/\?/g, '$question')
        .replace(/\~/g, '$tilde')
        .replace(/\&/g, '$ampersand')
        .replace(/\|/g, '$pipe')
        .replace(/</g, '$lt')
        .replace(/>/g, '$gt')
        .replace(/=/g, '$eq');
}

function fileWrapper(body) {
    var useStrict = es.ExpressionStatement(es.Literal('use strict'));
    var newBody = [useStrict].concat(body);
    var fn = es.FunctionExpression(null, [], es.BlockStatement(newBody));
    return es.Program([es.CallExpression(fn, [])]);
}

var handlers = {
    Module: function(node) {
        var value = transformAst(node.expr);
        var expr = moduleExportsEq(value);
        var body = PREDEF.body.concat([expr]);
        return fileWrapper(body);
    },
    Script: function(node) {
        var value = transformAst(node.expr);
        var body = PREDEF.body.concat([value]);
        return fileWrapper(body);
    },
    GetMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_get'),
                [prop, obj]
            )
        );
    },
    CallMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        var args = ast.List(node.args);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_call'),
                [prop, obj, args]
            )
        );
    },
    GetProperty: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_get'),
                [prop, obj]
            )
        );
    },
    BinOp: function(node) {
        var assertBoolean = function(x) {
            return transformAst(
                ast.Call(
                    ast.Identifier('LANG$$assert_boolean'),
                    [x]
                )
            );
        };
        var d = node.operator.data;
        if (d === 'and' || d === 'or') {
            var op = {and: '&&', or: '||'}[d];
            var a = assertBoolean(node.left);
            var b = assertBoolean(node.right);
            return es.LogicalExpression(op, a, b);
        }
        var f = ast.Identifier(node.operator.data);
        var args = [node.left, node.right];
        return transformAst(ast.Call(f, args));
    },
    Identifier: function(node) {
        return es.Identifier(cleanIdentifier(node.data));
    },
    IdentifierExpression: function(node) {
        return transformAst(node.data);
    },
    Call: function(node) {
        var f = transformAst(node.f);
        var args = node.args.map(transformAst);
        return es.CallExpression(f, args);
    },
    Parameter: function(node) {
        return transformAst(node.identifier);
    },
    Function: function(node) {
        var params = node
            .parameters
            .map(transformAst);
        var returnExpr = es.ReturnStatement(transformAst(node.body));
        var n = node.parameters.length;
        var arityCheck = esprima.parse(
            "if (arguments.length !== " + n + ") { " +
            "throw new LANG$$js_Error(" +
                "'expected " + n + " argument(s), " +
                "got ' + arguments.length" +
                "); " +
            "}"
        ).body;
        var preCheck = esprima.parse(
            "if (metadata.pre && !metadata.pre.apply(null, arguments)) {" +
                "throw new LANG$$js_Error(" +
                    "'Failed precondition'" +
                ");" +
            "}"
        ).body;
        var metadata = es.VariableDeclaration('var', [
            es.VariableDeclarator(
                es.Identifier('metadata'),
                transformAst(node.metadata)
            )
        ]);
        var body = flatten([
            arityCheck,
            preCheck,
            [returnExpr]
        ]);
        var innerFn = es.FunctionExpression(
            null,
            params,
            es.BlockStatement(body)
        );
        var outerFn = es.FunctionExpression(
            null,
            [],
            es.BlockStatement([
                metadata,
                es.ReturnStatement(innerFn)
            ])
        );
        return es.CallExpression(outerFn, []);
    },
    If: function(node) {
        var p = transformAst(node.p);
        var t = transformAst(node.t);
        var f = transformAst(node.f);
        return es.ConditionalExpression(p, t, f);
    },
    Binding: function(node) {
        var identifier = transformAst(node.identifier);
        var value = transformAst(node.value);
        return es.VariableDeclaration('var', [
            es.VariableDeclarator(identifier, value)
        ]);
    },
    Let: function(node) {
        var declarations = node.bindings.map(transformAst);
        var e = transformAst(node.expr);
        var returnExpr = es.ReturnStatement(e);
        var body = declarations.concat([returnExpr]);
        return es.CallExpression(
            es.FunctionExpression(
                null,
                [],
                es.BlockStatement(body)
            ),
            []
        );
    },
    List: function(node) {
        var pairs = node.data.map(transformAst);
        var array = es.ArrayExpression(pairs);
        var callee = es.Identifier('LANG$$freeze');
        return es.CallExpression(callee, [array]);
    },
    Pair: function(node) {
        return es.ArrayExpression([
            transformAst(node.key),
            transformAst(node.value)
        ]);
    },
    Map: function(node) {
        var pairs = node.data.map(transformAst);
        return es.CallExpression(
            es.Identifier('LANG$$object'),
            [es.ArrayExpression(pairs)]
        );
    },
    Number: literal,
    String: literal,
};

module.exports = transformAst;
<commit_msg>Now freezes function literals<commit_after>var isObject = require("lodash/lang/isObject");
var flatten = require("lodash/array/flatten");
var fs = require("fs");
var path = require("path");
var jsbeautify = require("js-beautify");
var esprima = require("esprima");
var es = require("./es");
var ast = require("./ast");

function transformAst(node) {
    if (!isObject(node)) {
        throw new Error("Not a node: " + jsonify(node));
    }
    if (handlers.hasOwnProperty(node.type)) {
        return handlers[node.type](node);
    }
    throw new Error("Unknown AST node: " + jsonify(node));
}

function jsonify(x) {
    return JSON.stringify(x);
}

function literal(node) {
    return es.Literal(node.data);
}

var PREDEF = require("./predef-ast");

function moduleExportsEq(x) {
    return es.ExpressionStatement(
        es.AssignmentExpression('=',
            es.MemberExpression(false,
                es.Identifier('module'),
                es.Identifier('exports')
            ),
            x
        )
    );
}

function cleanIdentifier(s) {
    if (/^if|else|while|do$/.test(s)) {
        return '$' + s;
    }
    return s
        .replace(/\+/g, '$plus')
        .replace(/-/g, '$minus')
        .replace(/\*/g, '$star')
        .replace(/\//g, '$slash')
        .replace(/!/g, '$bang')
        .replace(/;/g, '$semicolon')
        .replace(/@/g, '$at')
        .replace(/\?/g, '$question')
        .replace(/\~/g, '$tilde')
        .replace(/\&/g, '$ampersand')
        .replace(/\|/g, '$pipe')
        .replace(/</g, '$lt')
        .replace(/>/g, '$gt')
        .replace(/=/g, '$eq');
}

function fileWrapper(body) {
    var useStrict = es.ExpressionStatement(es.Literal('use strict'));
    var newBody = [useStrict].concat(body);
    var fn = es.FunctionExpression(null, [], es.BlockStatement(newBody));
    return es.Program([es.CallExpression(fn, [])]);
}

var handlers = {
    Module: function(node) {
        var value = transformAst(node.expr);
        var expr = moduleExportsEq(value);
        var body = PREDEF.body.concat([expr]);
        return fileWrapper(body);
    },
    Script: function(node) {
        var value = transformAst(node.expr);
        var body = PREDEF.body.concat([value]);
        return fileWrapper(body);
    },
    GetMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_get'),
                [prop, obj]
            )
        );
    },
    CallMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        var args = ast.List(node.args);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_call'),
                [prop, obj, args]
            )
        );
    },
    GetProperty: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_get'),
                [prop, obj]
            )
        );
    },
    BinOp: function(node) {
        var assertBoolean = function(x) {
            return transformAst(
                ast.Call(
                    ast.Identifier('LANG$$assert_boolean'),
                    [x]
                )
            );
        };
        var d = node.operator.data;
        if (d === 'and' || d === 'or') {
            var op = {and: '&&', or: '||'}[d];
            var a = assertBoolean(node.left);
            var b = assertBoolean(node.right);
            return es.LogicalExpression(op, a, b);
        }
        var f = ast.Identifier(node.operator.data);
        var args = [node.left, node.right];
        return transformAst(ast.Call(f, args));
    },
    Identifier: function(node) {
        return es.Identifier(cleanIdentifier(node.data));
    },
    IdentifierExpression: function(node) {
        return transformAst(node.data);
    },
    Call: function(node) {
        var f = transformAst(node.f);
        var args = node.args.map(transformAst);
        return es.CallExpression(f, args);
    },
    Parameter: function(node) {
        return transformAst(node.identifier);
    },
    Function: function(node) {
        var params = node
            .parameters
            .map(transformAst);
        var returnExpr = es.ReturnStatement(transformAst(node.body));
        var n = node.parameters.length;
        var arityCheck = esprima.parse(
            "if (arguments.length !== " + n + ") { " +
            "throw new LANG$$js_Error(" +
                "'expected " + n + " argument(s), " +
                "got ' + arguments.length" +
                "); " +
            "}"
        ).body;
        var preCheck = esprima.parse(
            "if (metadata.pre && !metadata.pre.apply(null, arguments)) {" +
                "throw new LANG$$js_Error(" +
                    "'Failed precondition'" +
                ");" +
            "}"
        ).body;
        var metadata = es.VariableDeclaration('var', [
            es.VariableDeclarator(
                es.Identifier('metadata'),
                transformAst(node.metadata)
            )
        ]);
        var body = flatten([
            arityCheck,
            preCheck,
            [returnExpr]
        ]);
        var innerFn = es.FunctionExpression(
            null,
            params,
            es.BlockStatement(body)
        );
        var callee = es.Identifier('LANG$$freeze');
        var frozen = es.CallExpression(callee, [innerFn]);
        var outerFn = es.FunctionExpression(
            null,
            [],
            es.BlockStatement([
                metadata,
                es.ReturnStatement(frozen)
            ])
        );
        return es.CallExpression(outerFn, []);
    },
    If: function(node) {
        var p = transformAst(node.p);
        var t = transformAst(node.t);
        var f = transformAst(node.f);
        return es.ConditionalExpression(p, t, f);
    },
    Binding: function(node) {
        var identifier = transformAst(node.identifier);
        var value = transformAst(node.value);
        return es.VariableDeclaration('var', [
            es.VariableDeclarator(identifier, value)
        ]);
    },
    Let: function(node) {
        var declarations = node.bindings.map(transformAst);
        var e = transformAst(node.expr);
        var returnExpr = es.ReturnStatement(e);
        var body = declarations.concat([returnExpr]);
        return es.CallExpression(
            es.FunctionExpression(
                null,
                [],
                es.BlockStatement(body)
            ),
            []
        );
    },
    List: function(node) {
        var pairs = node.data.map(transformAst);
        var array = es.ArrayExpression(pairs);
        var callee = es.Identifier('LANG$$freeze');
        return es.CallExpression(callee, [array]);
    },
    Pair: function(node) {
        return es.ArrayExpression([
            transformAst(node.key),
            transformAst(node.value)
        ]);
    },
    Map: function(node) {
        var pairs = node.data.map(transformAst);
        return es.CallExpression(
            es.Identifier('LANG$$object'),
            [es.ArrayExpression(pairs)]
        );
    },
    Number: literal,
    String: literal,
};

module.exports = transformAst;
<|endoftext|>


<commit_before>const test = require('tape')
const BorrowState = require('../lib/module.js')

const countTo = (num) => {
  let array = []
  for (let i = 0; i < num; i += 1) {
    array.push(i + 1)
  }
  return array
}

test(`strict-order`, (t) => {
  t.plan(1)
  let hasHappened = []
  let myState = new BorrowState()
  myState.block().then((state) => {
    hasHappened.push(1)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(2)
    return state
  }).then((state) => {
    hasHappened.push(3)
    return state
  }).then((state) => {
    hasHappened.push(4)
    return state
  }).then((state) => {
    hasHappened.push(5)
    return state
  }).then((state) => {
    hasHappened.push(6)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(7)
    return state
  }).then((state) => {
    hasHappened.push(8)
    return state
  }).then((state) => {
    hasHappened.push(9)
    return state
  }).then((state) => {
    hasHappened.push(10)
    return state
  }).then((state) => {
    hasHappened.push(11)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(12)
    t.equal(hasHappened, countTo(12), 'The operations happened in the right order')
    state.unblock()
  })
})
<commit_msg>Use test/count-to.js in strict-order test<commit_after>const test = require('tape')
const BorrowState = require('../lib/module.js')

const countTo = require('./count-to.js')

test(`strict-order`, (t) => {
  t.plan(1)
  let hasHappened = []
  let myState = new BorrowState()
  myState.block().then((state) => {
    hasHappened.push(1)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(2)
    return state
  }).then((state) => {
    hasHappened.push(3)
    return state
  }).then((state) => {
    hasHappened.push(4)
    return state
  }).then((state) => {
    hasHappened.push(5)
    return state
  }).then((state) => {
    hasHappened.push(6)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(7)
    return state
  }).then((state) => {
    hasHappened.push(8)
    return state
  }).then((state) => {
    hasHappened.push(9)
    return state
  }).then((state) => {
    hasHappened.push(10)
    return state
  }).then((state) => {
    hasHappened.push(11)
    state.unblock()
  })

  myState.block().then((state) => {
    hasHappened.push(12)
    t.equal(hasHappened, countTo(12), 'The operations happened in the right order')
    state.unblock()
  })
})
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CanvasView
 * @class
 * @private
 */
var CanvasView = View.extend(/** @lends CanvasView# */{
	_class: 'CanvasView',

	/**
	 * Creates a view object that wraps a canvas element.
	 *
	 * @name CanvasView#initialize
	 * @param {HTMLCanvasElement} canvas the canvas object that this view should
	 * wrap
	 */
	/**
	 * Creates a view object that wraps a newly created canvas element.
	 *
	 * @name CanvasView#initialize
	 * @param {Size} size the size of the canvas to be created
	 */
	initialize: function CanvasView(canvas) {
		// Handle canvas argument
		if (!(canvas instanceof HTMLCanvasElement)) {
			// See if the arguments describe the view size:
			var size = Size.read(arguments);
			if (size.isZero())
				throw new Error(
						'Cannot create CanvasView with the provided argument: '
						+ canvas);
			canvas = CanvasProvider.getCanvas(size);
		}
		this._context = canvas.getContext('2d');
		// Have Item count installed mouse events.
		this._eventCounters = {};
		this._ratio = 1;
/*#*/ if (__options.environment == 'browser') {
		if (PaperScope.getAttribute(canvas, 'hidpi') !== 'off') {
			// Hi-DPI Canvas support based on:
			// http://www.html5rocks.com/en/tutorials/canvas/hidpi/
			var deviceRatio = window.devicePixelRatio || 1,
				backingStoreRatio = DomElement.getPrefixValue(this._context,
						'backingStorePixelRatio') || 1;
			this._ratio = deviceRatio / backingStoreRatio;
		}
/*#*/ } // __options.environment == 'browser'
		View.call(this, canvas);
	},

	_setViewSize: function(size) {
		var width = size.width,
			height = size.height,
			ratio = this._ratio,
			element = this._element,
			style = element.style;
		// Upscale the canvas if the two ratios don't match.
		element.width = width * ratio;
		element.height = height * ratio;
		if (ratio !== 1) {
			style.width = width + 'px';
			style.height = height + 'px';
			// Now scale the context to counter the fact that we've manually
			// scaled our canvas element.
			this._context.scale(ratio, ratio);
		}
	},

	/**
	 * Draws the view.
	 *
	 * @name View#draw
	 * @function
	 */
	draw: function(checkRedraw) {
		if (checkRedraw && !this._project._needsRedraw)
			return false;
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		var ctx = this._context,
			size = this._viewSize;
		ctx.clearRect(0, 0, size.width + 1, size.height + 1);
		this._project.draw(ctx, this._matrix, this._ratio);
		this._project._needsRedraw = false;
		return true;
	}
}, new function() { // Item based mouse handling:

	var downPoint,
		lastPoint,
		overPoint,
		downItem,
		lastItem,
		overItem,
		hasDrag,
		doubleClick,
		clickTime;

	// Returns true if event was stopped, false otherwise, whether handler was
	// called or not!
	function callEvent(type, event, point, target, lastPoint) {
		var item = target,
			mouseEvent;
		// Bubble up the DOM and find a parent that responds to this event.
		while (item) {
			if (item.responds(type)) {
				// Create an reuse the event object if we're bubbling
				if (!mouseEvent)
					mouseEvent = new MouseEvent(type, event, point, target,
							// Calculate delta if lastPoint was passed
							lastPoint ? point.subtract(lastPoint) : null);
				if (item.fire(type, mouseEvent) && mouseEvent.isStopped) {
					// Call preventDefault() on native event if mouse event was
					// handled here.
					event.preventDefault();
					return true;
				}
			}
			item = item.getParent();
		}
		return false;
	}

	return {
		/**
		 * Returns true if event was stopped, false otherwise, whether handler
		 * was called or not!
		 */
		_handleEvent: function(type, point, event) {
			// Drop out if we don't have any event handlers for this type
			if (!this._eventCounters[type])
				return;
			// Run the hit-test first
			var project = this._project,
				hit = project.hitTest(point, {
					tolerance: project.options.hitTolerance || 0,
					fill: true,
					stroke: true
				}),
				item = hit && hit.item,
				stopped = false;
			// Now handle the mouse events
			switch (type) {
			case 'mousedown':
				stopped = callEvent(type, event, point, item);
				// See if we're clicking again on the same item, within the
				// double-click time. Firefox uses 300ms as the max time
				// difference:
				doubleClick = lastItem == item && (Date.now() - clickTime < 300);
				downItem = lastItem = item;
				downPoint = lastPoint = overPoint = point;
				hasDrag = downItem && downItem.responds('mousedrag');
				break;
			case 'mouseup':
				// stopping mousup events does not prevent mousedrag / mousemove
				// hanlding here, but it does click / doubleclick
				stopped = callEvent(type, event, point, item, downPoint);
				if (hasDrag) {
					// If the point has changed since the last mousedrag event,
					// send another one
					if (lastPoint && !lastPoint.equals(point))
						callEvent('mousedrag', event, point, downItem,
								lastPoint);
					// If we end up over another item, send it a mousemove event
					// now. Use point as overPoint, so delta is (0, 0) since
					// this will be the first mousemove event for this item.
					if (item !== downItem) {
						overPoint = point;
						callEvent('mousemove', event, point, item, overPoint);
					}
				}
				if (!stopped && item === downItem) {
					clickTime = Date.now();
					callEvent(doubleClick && downItem.responds('doubleclick')
							? 'doubleclick' : 'click', event, downPoint, item);
					doubleClick = false;
				}
				downItem = null;
				hasDrag = false;
				break;
			case 'mousemove':
				// Allow both mousedrag and mousemove events to stop mousemove
				// events from reaching tools.
				if (hasDrag)
					stopped = callEvent('mousedrag', event, point, downItem,
							lastPoint);
				// TODO: Consider implementing this again? "If we have a
				// mousedrag event, do not send mousemove events to any
				// item while we're dragging."
				// For now, we let other items receive mousemove events even
				// during a drag event.
				// If we change the overItem, reset overPoint to point so
				// delta is (0, 0)
				if (!stopped) {
					if (item !== overItem)
						overPoint = point;
					stopped = callEvent(type, event, point, item, overPoint);
				}
				lastPoint = overPoint = point;
				if (item !== overItem) {
					callEvent('mouseleave', event, point, overItem);
					overItem = item;
					callEvent('mouseenter', event, point, item);
				}
				break;
			}
			return stopped;
		}
	};
});

/*#*/ if (__options.environment == 'node') {
// Node.js based image exporting code.
CanvasView.inject(new function() {
	// Utility function that converts a number to a string with
	// x amount of padded 0 digits:
	function toPaddedString(number, length) {
		var str = number.toString(10);
		for (var i = 0, l = length - str.length; i < l; i++) {
			str = '0' + str;
		}
		return str;
	}

	var fs = require('fs');

	return {
		// DOCS: CanvasView#exportFrames(param);
		exportFrames: function(param) {
			param = new Base({
				fps: 30,
				prefix: 'frame-',
				amount: 1
			}, param);
			if (!param.directory) {
				throw new Error('Missing param.directory');
			}
			var view = this,
				count = 0,
				frameDuration = 1 / param.fps,
				startTime = Date.now(),
				lastTime = startTime;

			// Start exporting frames by exporting the first frame:
			exportFrame(param);

			function exportFrame(param) {
				var filename = param.prefix + toPaddedString(count, 6) + '.png',
					path = param.directory + '/' + filename;
				var out = view.exportImage(path, function() {
					// When the file has been closed, export the next fame:
					var then = Date.now();
					if (param.onProgress) {
						param.onProgress({
							count: count,
							amount: param.amount,
							percentage: Math.round(count / param.amount
									* 10000) / 100,
							time: then - startTime,
							delta: then - lastTime
						});
					}
					lastTime = then;
					if (count < param.amount) {
						exportFrame(param);
					} else {
						// Call onComplete handler when finished:
						if (param.onComplete) {
							param.onComplete();
						}
					}
				});
				// Use new Base() to convert into a Base object, for #toString()
				view.fire('frame', new Base({
					delta: frameDuration,
					time: frameDuration * count,
					count: count
				}));
				count++;
			}
		},

		// DOCS: View#exportImage(path, callback);
		exportImage: function(path, callback) {
			this.draw();
			var out = fs.createWriteStream(path),
				stream = this._element.createPNGStream();
			// Pipe the png stream to the write stream:
			stream.pipe(out);
			if (callback) {
				out.on('close', callback);
			}
			return out;
		}
	};
});
/*#*/ } // __options.environment == 'node'
<commit_msg>Start implementing mouse events on view.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CanvasView
 * @class
 * @private
 */
var CanvasView = View.extend(/** @lends CanvasView# */{
	_class: 'CanvasView',

	/**
	 * Creates a view object that wraps a canvas element.
	 *
	 * @name CanvasView#initialize
	 * @param {HTMLCanvasElement} canvas the canvas object that this view should
	 * wrap
	 */
	/**
	 * Creates a view object that wraps a newly created canvas element.
	 *
	 * @name CanvasView#initialize
	 * @param {Size} size the size of the canvas to be created
	 */
	initialize: function CanvasView(canvas) {
		// Handle canvas argument
		if (!(canvas instanceof HTMLCanvasElement)) {
			// See if the arguments describe the view size:
			var size = Size.read(arguments);
			if (size.isZero())
				throw new Error(
						'Cannot create CanvasView with the provided argument: '
						+ canvas);
			canvas = CanvasProvider.getCanvas(size);
		}
		this._context = canvas.getContext('2d');
		// Have Item count installed mouse events.
		this._eventCounters = {};
		this._ratio = 1;
/*#*/ if (__options.environment == 'browser') {
		if (PaperScope.getAttribute(canvas, 'hidpi') !== 'off') {
			// Hi-DPI Canvas support based on:
			// http://www.html5rocks.com/en/tutorials/canvas/hidpi/
			var deviceRatio = window.devicePixelRatio || 1,
				backingStoreRatio = DomElement.getPrefixValue(this._context,
						'backingStorePixelRatio') || 1;
			this._ratio = deviceRatio / backingStoreRatio;
		}
/*#*/ } // __options.environment == 'browser'
		View.call(this, canvas);
	},

	_setViewSize: function(size) {
		var width = size.width,
			height = size.height,
			ratio = this._ratio,
			element = this._element,
			style = element.style;
		// Upscale the canvas if the two ratios don't match.
		element.width = width * ratio;
		element.height = height * ratio;
		if (ratio !== 1) {
			style.width = width + 'px';
			style.height = height + 'px';
			// Now scale the context to counter the fact that we've manually
			// scaled our canvas element.
			this._context.scale(ratio, ratio);
		}
	},

	/**
	 * Draws the view.
	 *
	 * @name View#draw
	 * @function
	 */
	draw: function(checkRedraw) {
		if (checkRedraw && !this._project._needsRedraw)
			return false;
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		var ctx = this._context,
			size = this._viewSize;
		ctx.clearRect(0, 0, size.width + 1, size.height + 1);
		this._project.draw(ctx, this._matrix, this._ratio);
		this._project._needsRedraw = false;
		return true;
	}
}, new function() { // Item based mouse handling:

	var downPoint,
		lastPoint,
		overPoint,
		downItem,
		lastItem,
		overItem,
		hasDrag,
		dblClick,
		clickTime;

	// Returns true if event was stopped, false otherwise, whether handler was
	// called or not!
	function callEvent(view, type, event, point, target, lastPoint) {
		var item = target,
			mouseEvent;

		function call(obj) {
			if (obj.responds(type)) {
				// Only produce the event object if we really need it, and then
				// reuse it if we're bubbling.
				if (!mouseEvent) {
					mouseEvent = new MouseEvent(type, event, point, target,
							// Calculate delta if lastPoint was passed
							lastPoint ? point.subtract(lastPoint) : null);
				}
				if (obj.fire(type, mouseEvent) && mouseEvent.isStopped) {
					// Call preventDefault() on native event if mouse event was
					// handled here.
					event.preventDefault();
					return true;
				}
			}
		}

		// Bubble up the DOM and find a parent that responds to this event.
		while (item) {
			if (call(item))
				return true;
			item = item.getParent();
		}
		// Also call event handler on view, if installed.
		if (call(view))
			return true;
		return false;
	}

	return {
		/**
		 * Returns true if event was stopped, false otherwise, whether handler
		 * was called or not!
		 */
		_handleEvent: function(type, point, event) {
			// Drop out if we don't have any event handlers for this type
			if (!this._eventCounters[type])
				return;
			// Run the hit-test first
			var project = this._project,
				hit = project.hitTest(point, {
					tolerance: project.options.hitTolerance || 0,
					fill: true,
					stroke: true
				}),
				item = hit && hit.item,
				stopped = false;
			// Now handle the mouse events
			switch (type) {
			case 'mousedown':
				stopped = callEvent(this, type, event, point, item);
				// See if we're clicking again on the same item, within the
				// double-click time. Firefox uses 300ms as the max time
				// difference:
				dblClick = lastItem == item && (Date.now() - clickTime < 300);
				downItem = lastItem = item;
				downPoint = lastPoint = overPoint = point;
				hasDrag = downItem && downItem.responds('mousedrag');
				break;
			case 'mouseup':
				// stopping mousup events does not prevent mousedrag / mousemove
				// hanlding here, but it does click / doubleclick
				stopped = callEvent(this, type, event, point, item, downPoint);
				if (hasDrag) {
					// If the point has changed since the last mousedrag event,
					// send another one
					if (lastPoint && !lastPoint.equals(point))
						callEvent(this, 'mousedrag', event, point, downItem,
								lastPoint);
					// If we end up over another item, send it a mousemove event
					// now. Use point as overPoint, so delta is (0, 0) since
					// this will be the first mousemove event for this item.
					if (item !== downItem) {
						overPoint = point;
						callEvent(this, 'mousemove', event, point, item,
								overPoint);
					}
				}
				if (!stopped && item && item === downItem) {
					clickTime = Date.now();
					callEvent(this, dblClick && downItem.responds('doubleclick')
							? 'doubleclick' : 'click', event, downPoint, item);
					dblClick = false;
				}
				downItem = null;
				hasDrag = false;
				break;
			case 'mousemove':
				// Allow both mousedrag and mousemove events to stop mousemove
				// events from reaching tools.
				if (hasDrag)
					stopped = callEvent(this, 'mousedrag', event, point,
							downItem, lastPoint);
				// TODO: Consider implementing this again? "If we have a
				// mousedrag event, do not send mousemove events to any
				// item while we're dragging."
				// For now, we let other items receive mousemove events even
				// during a drag event.
				// If we change the overItem, reset overPoint to point so
				// delta is (0, 0)
				if (!stopped) {
					if (item !== overItem)
						overPoint = point;
					stopped = callEvent(this, type, event, point, item,
							overPoint);
				}
				lastPoint = overPoint = point;
				if (item !== overItem) {
					callEvent(this, 'mouseleave', event, point, overItem);
					overItem = item;
					callEvent(this, 'mouseenter', event, point, item);
				}
				break;
			}
			return stopped;
		}
	};
});

/*#*/ if (__options.environment == 'node') {
// Node.js based image exporting code.
CanvasView.inject(new function() {
	// Utility function that converts a number to a string with
	// x amount of padded 0 digits:
	function toPaddedString(number, length) {
		var str = number.toString(10);
		for (var i = 0, l = length - str.length; i < l; i++) {
			str = '0' + str;
		}
		return str;
	}

	var fs = require('fs');

	return {
		// DOCS: CanvasView#exportFrames(param);
		exportFrames: function(param) {
			param = new Base({
				fps: 30,
				prefix: 'frame-',
				amount: 1
			}, param);
			if (!param.directory) {
				throw new Error('Missing param.directory');
			}
			var view = this,
				count = 0,
				frameDuration = 1 / param.fps,
				startTime = Date.now(),
				lastTime = startTime;

			// Start exporting frames by exporting the first frame:
			exportFrame(param);

			function exportFrame(param) {
				var filename = param.prefix + toPaddedString(count, 6) + '.png',
					path = param.directory + '/' + filename;
				var out = view.exportImage(path, function() {
					// When the file has been closed, export the next fame:
					var then = Date.now();
					if (param.onProgress) {
						param.onProgress({
							count: count,
							amount: param.amount,
							percentage: Math.round(count / param.amount
									* 10000) / 100,
							time: then - startTime,
							delta: then - lastTime
						});
					}
					lastTime = then;
					if (count < param.amount) {
						exportFrame(param);
					} else {
						// Call onComplete handler when finished:
						if (param.onComplete) {
							param.onComplete();
						}
					}
				});
				// Use new Base() to convert into a Base object, for #toString()
				view.fire('frame', new Base({
					delta: frameDuration,
					time: frameDuration * count,
					count: count
				}));
				count++;
			}
		},

		// DOCS: View#exportImage(path, callback);
		exportImage: function(path, callback) {
			this.draw();
			var out = fs.createWriteStream(path),
				stream = this._element.createPNGStream();
			// Pipe the png stream to the write stream:
			stream.pipe(out);
			if (callback) {
				out.on('close', callback);
			}
			return out;
		}
	};
});
/*#*/ } // __options.environment == 'node'
<|endoftext|>


<commit_before>const fetch = require('node-fetch');
const assert = require('assert');
const analyzerAPIUrl = 'https://makefast.app.baqend.com/v1';
const analyzerCodeUrl = `${analyzerAPIUrl}/code`;

async function testAnalyzer(siteUrl, expectedUrlInfo, speedKitConfigString) {

  // Test Ratelimit
  const rateLimit = await fetch(`${analyzerCodeUrl}/testRateLimited`);

  if (!rateLimit.ok) {
    reportError(`Rate Limit Request failed with status: ${rateLimit.status}`);
  }

  console.log('Ratelimit Check ok');

  // Test NormalizeUrl
  const urlInfoBody = `{"urls": "${siteUrl}", "mobile": false}`;
  const urlInfoRes = await post(`${analyzerCodeUrl}/normalizeUrl`, urlInfoBody);

  if (!urlInfoRes.ok) {
    reportError(`Normalize Url Request failed with status: ${urlInfoRes.status}: ${urlInfoRes.statusText}`);
  }

  const urlInfo = await urlInfoRes.json();

  assert.deepEqual(expectedUrlInfo, urlInfo, `Unexpected Response from normalizeUrl. Expected: ${JSON.stringify(expectedUrlInfo)}. Given: ${JSON.stringify(urlInfo)}`);

  console.log('Normalize URL ok');

  // Test GenerateUniqueId

  const uniqueIdRes = await post(`${analyzerCodeUrl}/generateUniqueId`, '{"entityClass":"TestOverview"}');
  if (!uniqueIdRes.ok) {
    reportError(`Unique Id request failed with status: ${uniqueIdRes.status}: ${uniqueIdRes.statusText}`);
  }
  console.log('Unique ID ok');

  // Test QueueTest

  const compBody = {
    url: urlInfo[0].url,
    isSpeedKitComparison: urlInfo[0].speedkit,
    location: "eu-central-1:Chrome.Native",
    isClone:false,
    caching:false,
    mobile:false
  };

  const compTestRes = await post(`${analyzerCodeUrl}/queueTest`, JSON.stringify(compBody));

  if (!compTestRes.ok) {
    reportError(`Queue Test Competitor Request failed with status: ${compTestRes.status}: ${compTestRes.statusText}`);
  }

  const skBody = {
    url: urlInfo[0].url,
    isSpeedKitComparison: urlInfo[0].speedkit,
    speedKitConfig: speedKitConfigString,
    location: "eu-central-1:Chrome.Native",
    isClone:true,
    caching:false,
    mobile:false};

  const skTestRes = await post(`${analyzerCodeUrl}/queueTest`, JSON.stringify(skBody));

  if (!skTestRes.ok) {
    reportError(`Queue Test Speed Kit Request failed with status: ${skTestRes.status}: ${skTestRes.statusText}. Body: ${await skTestRes.text()}`);
  }

  const compId = (await compTestRes.json()).baqendId;
  const skId = (await skTestRes.json()).baqendId;

  console.log('Queue Test ok');

  // Test Test Results

  // Wait for tests to finish
  console.log('Waiting for Results');
  await waitAndReport(120);

  const compResultRes = await fetch(`${analyzerAPIUrl}/db/TestResult/${compId}`);

  if (!compResultRes.ok) {
    reportError(`Competitor Test Result Request failed with status: ${compResultRes.status}: ${compResultRes.statusText}`);
  }

  const skResultRes = await fetch(`${analyzerAPIUrl}/db/TestResult/${skId}`);

  if (!skResultRes.ok) {
    reportError(`Speed Kit Test Result Request failed with status: ${skResultRes.status}: ${skResultRes.statusText}`);
  }

  const compResult = await compResultRes.json();
  const skResult = await skResultRes.json();

  checkTestResult(compResult, false);

  console.log('Competitor Test OK');
  checkTestResult(skResult, true);

  console.log('Speed Kit Test OK');
  console.log(`Test Successful. Speedup: ${(compResult.firstView.speedIndex - skResult.firstView.speedIndex)}ms SI -- ${(compResult.firstView.firstMeaningfulPaint - skResult.firstView.firstMeaningfulPaint)}ms FMP`);

}

async function waitAndReport(time) {
  for (let i = 0; i < time; i += 10) {
    console.log(`${time - i}s to go`);
    await (new Promise(resolve => setTimeout(resolve, 10000)));
  }
}

function reportError(msg, err) {
  throw new Error(msg, err);
}

function checkTestResult(result, speedKit) {
  try {
    assert.ok(result.firstView, "First View missing");
    assert.ok(result.firstView.speedIndex, "Speed Index missing");
    assert.ok(result.firstView.firstMeaningfulPaint, "First Meaningful Paint missing");
    assert.ok(result.url, "Url missing");
    assert.ok(result.summaryUrl, "Summary Link missing");
    assert.ok(result.videoIdFirstView, "Video Id missing");
    assert.ok(result.videoFileFirstView, "Video File missing");
    assert.ok(!result.testDataMissing, "Test Data missing");
    assert.ok(result.hasFinished, "Test not finished");
    assert.ok(!result.isWordPress, "Testpage wrongly categoriezed as WordPress");
    assert.equal(0, result.priority, "Priority not 0");
  } catch(err) {
    console.log(err);
    reportError(`Testresult for ${speedKit? 'Speed Kit' : 'Competitor'} not valid. Id: ${result.id}`, err);
  }
}

async function post(url, body) {
  const headers = {};
  headers['content-type'] = 'application/json;charset=UTF-8';

  return fetch(url, { method: 'POST', headers, body});
}

async function executeAnalyzerTest() {
  try {
    console.log('Testing kicker.de (no Speed Kit installed)');
    await execNonSpeedKit();
    console.log('Testing fussballdaten.de (with Speed Kit installed)');
    await execSpeedKit();
  } catch(err) {
    console.error(err.stack, err.cause);
    process.exit(1);
  }
}

executeAnalyzerTest();

async function execNonSpeedKit() {
  const expectedUrlInfo = [{
    query: "kicker.de",
    url: "http://www.kicker.de/",
    displayUrl: "http://www.kicker.de/",
    isBaqendApp: false,
    isSecured: false,
    speedkit: false,
    speedkitVersion: null,
    type: null
  }];

  const speedKitConfigString = '{"appName": "makefast", "whitelist": [{ "host": [ /^(?:[\\w-]*\\.){0,3}(?:kicker\\.)/ ] }], "userAgentDetection": false }';

  return testAnalyzer(expectedUrlInfo[0].query, expectedUrlInfo, speedKitConfigString)
}

async function execSpeedKit() {
  const expectedUrlInfo = [{
    query: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    url: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    displayUrl: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    isBaqendApp: false,
    isSecured: true,
    speedkit: true,
    speedkitVersion: "1.1.4",
    type: null
  }];

  const speedKitConfigString = '';

  return testAnalyzer(expectedUrlInfo[0].query, expectedUrlInfo, speedKitConfigString)
}
<commit_msg>Fix test to wait longer for results<commit_after>const fetch = require('node-fetch');
const assert = require('assert');
const analyzerAPIUrl = 'https://makefast.app.baqend.com/v1';
const analyzerCodeUrl = `${analyzerAPIUrl}/code`;

async function testAnalyzer(siteUrl, expectedUrlInfo, speedKitConfigString) {

  // Test Ratelimit
  const rateLimit = await fetch(`${analyzerCodeUrl}/testRateLimited`);

  if (!rateLimit.ok) {
    reportError(`Rate Limit Request failed with status: ${rateLimit.status}`);
  }

  console.log('Ratelimit Check ok');

  // Test NormalizeUrl
  const urlInfoBody = `{"urls": "${siteUrl}", "mobile": false}`;
  const urlInfoRes = await post(`${analyzerCodeUrl}/normalizeUrl`, urlInfoBody);

  if (!urlInfoRes.ok) {
    reportError(`Normalize Url Request failed with status: ${urlInfoRes.status}: ${urlInfoRes.statusText}`);
  }

  const urlInfo = await urlInfoRes.json();

  assert.deepEqual(expectedUrlInfo, urlInfo, `Unexpected Response from normalizeUrl. Expected: ${JSON.stringify(expectedUrlInfo)}. Given: ${JSON.stringify(urlInfo)}`);

  console.log('Normalize URL ok');

  // Test GenerateUniqueId

  const uniqueIdRes = await post(`${analyzerCodeUrl}/generateUniqueId`, '{"entityClass":"TestOverview"}');
  if (!uniqueIdRes.ok) {
    reportError(`Unique Id request failed with status: ${uniqueIdRes.status}: ${uniqueIdRes.statusText}`);
  }
  console.log('Unique ID ok');

  // Test QueueTest

  const compBody = {
    url: urlInfo[0].url,
    isSpeedKitComparison: urlInfo[0].speedkit,
    location: "eu-central-1:Chrome.Native",
    isClone:false,
    caching:false,
    mobile:false
  };

  const compTestRes = await post(`${analyzerCodeUrl}/queueTest`, JSON.stringify(compBody));

  if (!compTestRes.ok) {
    reportError(`Queue Test Competitor Request failed with status: ${compTestRes.status}: ${compTestRes.statusText}`);
  }

  const skBody = {
    url: urlInfo[0].url,
    isSpeedKitComparison: urlInfo[0].speedkit,
    speedKitConfig: speedKitConfigString,
    location: "eu-central-1:Chrome.Native",
    isClone:true,
    caching:false,
    mobile:false};

  const skTestRes = await post(`${analyzerCodeUrl}/queueTest`, JSON.stringify(skBody));

  if (!skTestRes.ok) {
    reportError(`Queue Test Speed Kit Request failed with status: ${skTestRes.status}: ${skTestRes.statusText}. Body: ${await skTestRes.text()}`);
  }

  const compId = (await compTestRes.json()).baqendId;
  const skId = (await skTestRes.json()).baqendId;

  console.log('Queue Test ok');

  // Test Test Results

  // Wait for tests to finish
  console.log('Waiting for Results');
  await waitAndReport(240);

  const compResultRes = await fetch(`${analyzerAPIUrl}/db/TestResult/${compId}`);

  if (!compResultRes.ok) {
    reportError(`Competitor Test Result Request failed with status: ${compResultRes.status}: ${compResultRes.statusText}`);
  }

  const skResultRes = await fetch(`${analyzerAPIUrl}/db/TestResult/${skId}`);

  if (!skResultRes.ok) {
    reportError(`Speed Kit Test Result Request failed with status: ${skResultRes.status}: ${skResultRes.statusText}`);
  }

  const compResult = await compResultRes.json();
  const skResult = await skResultRes.json();

  checkTestResult(compResult, false);

  console.log('Competitor Test OK');
  checkTestResult(skResult, true);

  console.log('Speed Kit Test OK');
  console.log(`Test Successful. Speedup: ${(compResult.firstView.speedIndex - skResult.firstView.speedIndex)}ms SI -- ${(compResult.firstView.firstMeaningfulPaint - skResult.firstView.firstMeaningfulPaint)}ms FMP`);

}

async function waitAndReport(time) {
  for (let i = 0; i < time; i += 10) {
    console.log(`${time - i}s to go`);
    await (new Promise(resolve => setTimeout(resolve, 10000)));
  }
}

function reportError(msg, err) {
  throw new Error(msg, err);
}

function checkTestResult(result, speedKit) {
  try {
    assert.ok(result.firstView, "First View missing");
    assert.ok(result.firstView.speedIndex, "Speed Index missing");
    assert.ok(result.firstView.firstMeaningfulPaint, "First Meaningful Paint missing");
    assert.ok(result.url, "Url missing");
    assert.ok(result.summaryUrl, "Summary Link missing");
    assert.ok(result.videoIdFirstView, "Video Id missing");
    assert.ok(result.videoFileFirstView, "Video File missing");
    assert.ok(!result.testDataMissing, "Test Data missing");
    assert.ok(result.hasFinished, "Test not finished");
    assert.ok(!result.isWordPress, "Testpage wrongly categoriezed as WordPress");
    assert.equal(0, result.priority, "Priority not 0");
  } catch(err) {
    console.log(err);
    reportError(`Testresult for ${speedKit? 'Speed Kit' : 'Competitor'} not valid. Id: ${result.id}`, err);
  }
}

async function post(url, body) {
  const headers = {};
  headers['content-type'] = 'application/json;charset=UTF-8';

  return fetch(url, { method: 'POST', headers, body});
}

async function executeAnalyzerTest() {
  try {
    console.log('Testing kicker.de (no Speed Kit installed)');
    await execNonSpeedKit();
    console.log('Testing fussballdaten.de (with Speed Kit installed)');
    await execSpeedKit();
  } catch(err) {
    console.error(err.stack, err.cause);
    process.exit(1);
  }
}

executeAnalyzerTest();

async function execNonSpeedKit() {
  const expectedUrlInfo = [{
    query: "kicker.de",
    url: "http://www.kicker.de/",
    displayUrl: "http://www.kicker.de/",
    isBaqendApp: false,
    isSecured: false,
    speedkit: false,
    speedkitVersion: null,
    type: null
  }];

  const speedKitConfigString = '{"appName": "makefast", "whitelist": [{ "host": [ /^(?:[\\w-]*\\.){0,3}(?:kicker\\.)/ ] }], "userAgentDetection": false }';

  return testAnalyzer(expectedUrlInfo[0].query, expectedUrlInfo, speedKitConfigString)
}

async function execSpeedKit() {
  const expectedUrlInfo = [{
    query: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    url: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    displayUrl: "https://www.fussballdaten.de/bundesliga/ewige-tabelle/",
    isBaqendApp: false,
    isSecured: true,
    speedkit: true,
    speedkitVersion: "1.1.4",
    type: null
  }];

  const speedKitConfigString = '';

  return testAnalyzer(expectedUrlInfo[0].query, expectedUrlInfo, speedKitConfigString)
}
<|endoftext|>


<commit_before>/**
 * Easy way to get CSS in the JS by appending it to the body during
 * construction of the UI
 */
export default `
.d3-scale-interactive-main {
  font-weight: 200;
  position: fixed;
  right: 10px;
  top: 0px;
  background: #242424;
  font-size: 12px;
  width: 280px;
  color: #fff;
  overflow: auto;
}

.d3-scale-interactive-hidden .d3-scale-interactive-main-inner {
  display: none;
}

.d3-scale-interactive-main-inner {
  min-height: 50px;
}

.d3-scale-interactive-main-toggle {
  font-size: 11px;
  color: #ccc;
  padding: 6px 10px;
  cursor: pointer;
  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  user-select: none;
}

.d3-scale-interactive-main-toggle:hover {
  background: #444;
  color: #fff;
}

.d3-scale-interactive-panel {
  position: relative;
  background: rgba(0, 0, 0, 0.3);
  padding: 10px;
  margin-bottom: 5px;
  border-bottom: 1px solid #111;
}

.d3-scale-interactive-type-selector select {
  margin-right: 6px;
}

.d3-scale-interactive-panel a {
  color: #039898;
  text-decoration: none;
}

.d3-scale-interactive-panel a:hover {
  text-decoration: underline;
  color: #04b5b5;
}

.d3-scale-interactive-message-container {
  pointer-events: none;
  position: absolute;
  right: 2px;
  top: 2px;
  padding: 5px 15px;
  background: #054e4e;
  opacity: 0;
  transition: opacity .5s;
}

.d3-scale-interactive-message-container.d3-scale-interactive-visible {
  opacity: 1;
  transition: opacity .1s;
}

.d3-scale-interactive-scale-controls {
  margin-bottom: 4px;
}

.d3-scale-interactive-panel-inner {
  clear: both;
}

.d3-scale-interactive-hidden .d3-scale-interactive-panel-inner {
  display: none;
}

.d3-scale-interactive-hidden.d3-scale-interactive-panel {
  padding-bottom: 0;
}

.d3-scale-interactive-hidden.d3-scale-interactive-panel h3 {
  color: #ccc;
  font-weight: 200;
}

.d3-scale-interactive-panel:last-child {
  margin-bottom: 0;
}

.d3-scale-interactive-panel-item {
  margin-bottom: 8px;
}

.d3-scale-interactive-panel-item:last-child {
  margin-bottom: 0;
}

.d3-scale-interactive-panel h3 {
  padding: 5px;
  margin: -5px -5px 0;
  font-size: 12px;
  text-transform: uppercase;
  cursor: pointer;
}

.d3-scale-interactive-panel h3:hover {
  background: #444;
  color: #fff;
  font-weight: 600;
}

.d3-scale-interactive-panel h4 {
  margin: 0 0 3px;
  font-size: 10px;
  font-weight: 200;
  text-transform: uppercase;
  color: #ccc;
}

.d3-scale-interactive-panel input {
  font-family: 'Source Code Pro', 'Monaco', 'Consolas', monospace;
  color: #000;
}

.d3-scale-interactive-input-entry-field {
  width: 150px;
  margin-bottom: 4px;
}

.d3-scale-interactive-input-entry-field.d3-scale-interactive-draggable {
  cursor: ns-resize;
}

.d3-scale-interactive-input-entry-add,
.d3-scale-interactive-input-entry-remove {
  box-sizing: content-box;
  display: inline-block;
  padding: 5px;
  background: #333;
  border-radius: 100%;
  height: 10px;
  width: 10px;
  text-align: center;
  line-height: 10px;
  font-weight: normal;
  color: #aaa;
  margin-left: 5px;
  cursor: pointer;
}

.d3-scale-interactive-input-entry-add:hover,
.d3-scale-interactive-input-entry-remove:hover {
  background: #111;
  color: #fff;
}

.d3-scale-interactive-input-entry-color {
  width: 30px;
  margin-left: 5px;
  outline: 0;
  background: transparent;
  border: 0;
  height: 19px;
}

.d3-scale-interactive-input-entry-remove.d3-scale-interactive-hidden,
.d3-scale-interactive-input-entry-color.d3-scale-interactive-hidden {
  display: none;
}

.d3-scale-interactive-main .d3-scale-interactive-reset-button {
  float: right;
}

.d3-scale-interactive-main button {
  font-size: 10px;
  text-transform: uppercase;
  display: inline-block;
  padding: 4px 12px;
  font-weight: 200;
  background-color: #333;
  border: 0;
  color: #aaa;
  cursor: pointer;
  margin: 0 4px 4px 0;
}

.d3-scale-interactive-main button.d3-scale-interactive-active,
.d3-scale-interactive-main button:hover {
  background-color: #111;
  color: #fff;
}

.d3-scale-interactive-color-bar-box {
  display: inline-block;
  height: 15px;
  border-radius: 0;
}
.d3-scale-interactive-stats-panel {
  margin-bottom: 8px;
}

.d3-scale-interactive-stats-chart .axis path,
.d3-scale-interactive-stats-chart .axis line {
  stroke: #444;
}
.d3-scale-interactive-stats-chart .axis text {
  fill: #777;
}

.d3-scale-interactive-stats-status {
  font-style: italic;
  color: #777;
  font-size: 11px;
}
`;
<commit_msg>Make hover/active buttons more obvious<commit_after>/**
 * Easy way to get CSS in the JS by appending it to the body during
 * construction of the UI
 */
export default `
.d3-scale-interactive-main {
  font-weight: 200;
  position: fixed;
  right: 10px;
  top: 0px;
  background: #242424;
  font-size: 12px;
  width: 280px;
  color: #fff;
  overflow: auto;
}

.d3-scale-interactive-hidden .d3-scale-interactive-main-inner {
  display: none;
}

.d3-scale-interactive-main-inner {
  min-height: 50px;
}

.d3-scale-interactive-main-toggle {
  font-size: 11px;
  color: #ccc;
  padding: 6px 10px;
  cursor: pointer;
  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  user-select: none;
}

.d3-scale-interactive-main-toggle:hover {
  background: #444;
  color: #fff;
}

.d3-scale-interactive-panel {
  position: relative;
  background: rgba(0, 0, 0, 0.3);
  padding: 10px;
  margin-bottom: 5px;
  border-bottom: 1px solid #111;
}

.d3-scale-interactive-type-selector select {
  margin-right: 6px;
}

.d3-scale-interactive-panel a {
  color: #039898;
  text-decoration: none;
}

.d3-scale-interactive-panel a:hover {
  text-decoration: underline;
  color: #04b5b5;
}

.d3-scale-interactive-message-container {
  pointer-events: none;
  position: absolute;
  right: 2px;
  top: 2px;
  padding: 5px 15px;
  background: #054e4e;
  opacity: 0;
  transition: opacity .5s;
}

.d3-scale-interactive-message-container.d3-scale-interactive-visible {
  opacity: 1;
  transition: opacity .1s;
}

.d3-scale-interactive-scale-controls {
  margin-bottom: 4px;
}

.d3-scale-interactive-panel-inner {
  clear: both;
}

.d3-scale-interactive-hidden .d3-scale-interactive-panel-inner {
  display: none;
}

.d3-scale-interactive-hidden.d3-scale-interactive-panel {
  padding-bottom: 0;
}

.d3-scale-interactive-hidden.d3-scale-interactive-panel h3 {
  color: #ccc;
  font-weight: 200;
}

.d3-scale-interactive-panel:last-child {
  margin-bottom: 0;
}

.d3-scale-interactive-panel-item {
  margin-bottom: 8px;
}

.d3-scale-interactive-panel-item:last-child {
  margin-bottom: 0;
}

.d3-scale-interactive-panel h3 {
  padding: 5px;
  margin: -5px -5px 0;
  font-size: 12px;
  text-transform: uppercase;
  cursor: pointer;
}

.d3-scale-interactive-panel h3:hover {
  background: #444;
  color: #fff;
  font-weight: 600;
}

.d3-scale-interactive-panel h4 {
  margin: 0 0 3px;
  font-size: 10px;
  font-weight: 200;
  text-transform: uppercase;
  color: #ccc;
}

.d3-scale-interactive-panel input {
  font-family: 'Source Code Pro', 'Monaco', 'Consolas', monospace;
  color: #000;
}

.d3-scale-interactive-input-entry-field {
  width: 150px;
  margin-bottom: 4px;
}

.d3-scale-interactive-input-entry-field.d3-scale-interactive-draggable {
  cursor: ns-resize;
}

.d3-scale-interactive-input-entry-add,
.d3-scale-interactive-input-entry-remove {
  box-sizing: content-box;
  display: inline-block;
  padding: 5px;
  background: #333;
  border-radius: 100%;
  height: 10px;
  width: 10px;
  text-align: center;
  line-height: 10px;
  font-weight: normal;
  color: #aaa;
  margin-left: 5px;
  cursor: pointer;
}

.d3-scale-interactive-input-entry-add:hover,
.d3-scale-interactive-input-entry-remove:hover {
  background: #111;
  color: #fff;
}

.d3-scale-interactive-input-entry-color {
  width: 30px;
  margin-left: 5px;
  outline: 0;
  background: transparent;
  border: 0;
  height: 19px;
}

.d3-scale-interactive-input-entry-remove.d3-scale-interactive-hidden,
.d3-scale-interactive-input-entry-color.d3-scale-interactive-hidden {
  display: none;
}

.d3-scale-interactive-main .d3-scale-interactive-reset-button {
  float: right;
}

.d3-scale-interactive-main button {
  font-size: 10px;
  text-transform: uppercase;
  display: inline-block;
  padding: 4px 8px;
  font-weight: 200;
  background-color: #333;
  border: 1px solid transparent;
  color: #aaa;
  cursor: pointer;
  margin: 0 4px 4px 0;
}

.d3-scale-interactive-main button.d3-scale-interactive-active,
.d3-scale-interactive-main button:hover {
  background-color: #111;
  color: #fff;
  border-color: #444;

}

.d3-scale-interactive-color-bar-box {
  display: inline-block;
  height: 15px;
  border-radius: 0;
}
.d3-scale-interactive-stats-panel {
  margin-bottom: 8px;
}

.d3-scale-interactive-stats-chart .axis path,
.d3-scale-interactive-stats-chart .axis line {
  stroke: #444;
}
.d3-scale-interactive-stats-chart .axis text {
  fill: #777;
}

.d3-scale-interactive-stats-status {
  font-style: italic;
  color: #777;
  font-size: 11px;
}
`;
<|endoftext|>


<commit_before>import { deepCollection } from './object'; // TODO NOPE
import { resourcePath } from './shared';
import path from 'path';

function getBaseUrl (resource, drizzleData) {
  const options = drizzleData.options;
  const destRoot = options.dest.root;
  const destResource = options.dest[
    Object.keys(options.keys).find(
      key => options.keys[key].singular === resource.resourceType
    )
  ];

  const baseurl = path.relative(
    path.dirname(resourcePath(resource.id, destResource)),
    destRoot
  );

  return baseurl === '' ? `.${baseurl}` : baseurl;
}

function resourceContext (resource, drizzleData) {
  const context = Object.assign({}, resource);
  context.drizzle = drizzleData;

  if (drizzleData.options.dest) {
    context.baseurl = getBaseUrl(resource, drizzleData);
  }

  if (typeof resource.data === 'object') {
    Object.keys(resource.data).map(dataKey =>
      context[dataKey] = resource.data[dataKey]);
    delete context.data;
  }
  return context;
}

/**
 */
function patternContext (pattern, drizzleData) {
  const context = resourceContext(pattern, drizzleData);
  // Get the collection for this pattern and add a reference to it
  context.collection = deepCollection(pattern.id, drizzleData.patterns);
  return context;
}

export { patternContext, resourceContext };
<commit_msg>Improve logic checking for `options.dest.root`<commit_after>import { deepCollection } from './object'; // TODO NOPE
import { resourcePath } from './shared';
import path from 'path';
import { pathSatisfies, is } from 'ramda';

function getBaseUrl (resource, drizzleData) {
  const options = drizzleData.options;
  const destRoot = options.dest.root;
  const destResource = options.dest[
    Object.keys(options.keys).find(
      key => options.keys[key].singular === resource.resourceType
    )
  ];

  const baseurl = path.relative(
    path.dirname(resourcePath(resource.id, destResource)),
    destRoot
  );

  return baseurl === '' ? `.${baseurl}` : baseurl;
}

function resourceContext (resource, drizzleData) {
  const context = Object.assign({}, resource);
  context.drizzle = drizzleData;

  if (pathSatisfies(is(String), ['dest', 'root'], drizzleData.options)) {
    context.baseurl = getBaseUrl(resource, drizzleData);
  }

  if (typeof resource.data === 'object') {
    Object.keys(resource.data).map(dataKey =>
      context[dataKey] = resource.data[dataKey]);
    delete context.data;
  }
  return context;
}

/**
 */
function patternContext (pattern, drizzleData) {
  const context = resourceContext(pattern, drizzleData);
  // Get the collection for this pattern and add a reference to it
  context.collection = deepCollection(pattern.id, drizzleData.patterns);
  return context;
}

export { patternContext, resourceContext };
<|endoftext|>


<commit_before>import MatrixClientPeg from '../MatrixClientPeg';

/**
 * Get all widgets (user and room) for the current user
 * @param  {object} room The room to get widgets for
 * @return {[object]} Array containing current / active room and user widget state events
 */
function getWidgets(room) {
    const widgets = getRoomWidgets(room);
    widgets.concat(getUserWidgets());
    return widgets;
}

/**
 * Get room specific widgets
 * @param  {object} room The room to get widgets force
 * @return {[object]} Array containing current / active room widgets
 */
function getRoomWidgets(room) {
    const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
    if (!appsStateEvents) {
        return [];
    }

    return appsStateEvents.filter((ev) => {
        return ev.getContent().type && ev.getContent().url;
    });
}

/**
 * Get user specific widgets (not linked to a specific room)
 * @return {[object]} Array containing current / active user widgets
 */
function getUserWidgets() {
    const client = MatrixClientPeg.get();
    if (!client) {
        throw new Error('User not logged in');
    }
    const userWidgets = client.getAccountData('m.widgets');
    let userWidgetContent = {};
    if (userWidgets && userWidgets.getContent()) {
      userWidgetContent = userWidgets.getContent();
    }
    return Object.keys(userWidgetContent).map((key) => userWidgetContent[key]);
}

/**
 * Get active stickerpack widgets (stickerpacks are user widgets by nature)
 * @return {[object]} Array containing current / active stickerpack widgets
 */
function getStickerpackWidgets() {
    const widgets = getUserWidgets();
    console.warn("widgets", widgets);
    const stickerpackWidgets = widgets.filter((widget) => widget.type='stickerpack');
    console.warn('Stickerpack widgets', stickerpackWidgets);
    return stickerpackWidgets;
}

/**
 * Remove all stickerpack widgets (stickerpacks are user widgets by nature)
 */
function removeStickerpackWidgets() {
    const client = MatrixClientPeg.get();
    if (!client) {
        throw new Error('User not logged in');
    }
    const userWidgets = client.getAccountData('m.widgets').getContent() || {};
    Object.entries(userWidgets).forEach(([key, widget]) => {
        if (widget.type === 'stickerpack') {
            delete userWidgets[key];
        }
    });
    client.setAccountData('m.widgets', userWidgets);
}

export default {
    getWidgets,
    getRoomWidgets,
    getUserWidgets,
    getStickerpackWidgets,
    removeStickerpackWidgets,
};
<commit_msg>Reduce logging.<commit_after>import MatrixClientPeg from '../MatrixClientPeg';

/**
 * Get all widgets (user and room) for the current user
 * @param  {object} room The room to get widgets for
 * @return {[object]} Array containing current / active room and user widget state events
 */
function getWidgets(room) {
    const widgets = getRoomWidgets(room);
    widgets.concat(getUserWidgets());
    return widgets;
}

/**
 * Get room specific widgets
 * @param  {object} room The room to get widgets force
 * @return {[object]} Array containing current / active room widgets
 */
function getRoomWidgets(room) {
    const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
    if (!appsStateEvents) {
        return [];
    }

    return appsStateEvents.filter((ev) => {
        return ev.getContent().type && ev.getContent().url;
    });
}

/**
 * Get user specific widgets (not linked to a specific room)
 * @return {[object]} Array containing current / active user widgets
 */
function getUserWidgets() {
    const client = MatrixClientPeg.get();
    if (!client) {
        throw new Error('User not logged in');
    }
    const userWidgets = client.getAccountData('m.widgets');
    let userWidgetContent = {};
    if (userWidgets && userWidgets.getContent()) {
      userWidgetContent = userWidgets.getContent();
    }
    return Object.keys(userWidgetContent).map((key) => userWidgetContent[key]);
}

/**
 * Get active stickerpack widgets (stickerpacks are user widgets by nature)
 * @return {[object]} Array containing current / active stickerpack widgets
 */
function getStickerpackWidgets() {
    const widgets = getUserWidgets();
    const stickerpackWidgets = widgets.filter((widget) => widget.type='stickerpack');
    return stickerpackWidgets;
}

/**
 * Remove all stickerpack widgets (stickerpacks are user widgets by nature)
 */
function removeStickerpackWidgets() {
    const client = MatrixClientPeg.get();
    if (!client) {
        throw new Error('User not logged in');
    }
    const userWidgets = client.getAccountData('m.widgets').getContent() || {};
    Object.entries(userWidgets).forEach(([key, widget]) => {
        if (widget.type === 'stickerpack') {
            delete userWidgets[key];
        }
    });
    client.setAccountData('m.widgets', userWidgets);
}

export default {
    getWidgets,
    getRoomWidgets,
    getUserWidgets,
    getStickerpackWidgets,
    removeStickerpackWidgets,
};
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

export { Button, ProgressBar } from 'react-native-ui-components';

export { AutocompleteSelector } from './AutocompleteSelector';
export { ExpiryTextInput } from './ExpiryTextInput';
export { FinaliseButton } from './FinaliseButton';
export { GenericChoiceList } from './GenericChoiceList';
export { IconCell } from './IconCell';
export { NavigationBar } from './NavigationBar';
export { OnePressButton } from './OnePressButton';
export { PageButton } from './PageButton';
export { PageInfo } from './PageInfo';
export { SequentialSteps } from './SequentialSteps';
export { Spinner } from './Spinner';
export { SyncState } from './SyncState';
export { TextEditor } from './TextEditor';
export { TextInput } from './TextInput';
export { ToggleBar } from './ToggleBar';
export { ToggleSelector } from './ToggleSelector';
export { NewExpiryDateInput } from './NewExpiryDateInput';
export {
  SortAscIcon,
  SortNeutralIcon,
  SortDescIcon,
  CheckedComponent,
  UncheckedComponent,
  DisabledCheckedComponent,
  DisabledUncheckedComponent,
} from './icons';
<commit_msg>Add export of Cancel icon<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

export { Button, ProgressBar } from 'react-native-ui-components';

export { AutocompleteSelector } from './AutocompleteSelector';
export { ExpiryTextInput } from './ExpiryTextInput';
export { FinaliseButton } from './FinaliseButton';
export { GenericChoiceList } from './GenericChoiceList';
export { IconCell } from './IconCell';
export { NavigationBar } from './NavigationBar';
export { OnePressButton } from './OnePressButton';
export { PageButton } from './PageButton';
export { PageInfo } from './PageInfo';
export { SequentialSteps } from './SequentialSteps';
export { Spinner } from './Spinner';
export { SyncState } from './SyncState';
export { TextEditor } from './TextEditor';
export { TextInput } from './TextInput';
export { ToggleBar } from './ToggleBar';
export { ToggleSelector } from './ToggleSelector';
export { NewExpiryDateInput } from './NewExpiryDateInput';
export {
  SortAscIcon,
  SortNeutralIcon,
  SortDescIcon,
  CheckedComponent,
  UncheckedComponent,
  DisabledCheckedComponent,
  DisabledUncheckedComponent,
  Cancel,
} from './icons';
<|endoftext|>


<commit_before>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var local = path.join.bind(path, __dirname);

describe("Remote", function() {
  var NodeGit = require(local("../../"));
  var Repository = require(local("../../lib/repository"));
  var Remote = require(local("../../lib/remote"));

  var reposPath = local("../repos/workdir/.git");
  var url = "https://github.com/nodegit/test";

  function removeOrigins(repository) {
    Remote.delete(repository, "origin1");
    Remote.delete(repository, "origin2");
    Remote.delete(repository, "origin3");
  }

  before(function() {
    var test = this;

    return Repository.open(reposPath)
      .then(function(repository) {
        test.repository = repository;

        return Remote.lookup(repository, "origin");
      })
      .then(function(remote) {
        test.remote = remote;

        return removeOrigins(test.repository);
      });
  });

  after(function() {
    return removeOrigins(this.repository);
  });

  it("can load a remote", function() {
    assert.ok(this.remote instanceof Remote);
  });

  it("can read the remote url", function() {
    assert.equal( this.remote.url().replace(".git", ""), url);
  });

  it("has an empty pushurl by default", function() {
    assert.equal(this.remote.pushurl(), undefined);
  });

  it("can set a remote", function() {
    var repository = this.repository;
    var newRemote;

    return Remote.create(repository, "origin1", url)
      .then(function(remote) {
        newRemote = remote;
        return remote.setPushurl("https://google.com/");
      })
      .then(function() {
        assert(newRemote.pushurl(), "https://google.com/");
      });
  });

  it("can read the remote name", function() {
    assert.equal(this.remote.name(), "origin");
  });

  it("can create and load a new remote", function() {
    var repository = this.repository;

    return Remote.create(repository, "origin2", url)
      .then(function() {
        return Remote.lookup(repository, "origin2");
      })
      .then(function(remote) {
        assert(remote.url(), url);
      });
  });

  it("can delete a remote", function() {
    var repository = this.repository;

    return Remote.create(repository, "origin3", url)
      .then(function(remote) {
        Remote.delete(repository, "origin3");
        return Remote.lookup(repository, "origin3");
      })
      .then(Promise.reject, Promise.resolve);
  });

  it("can download from a remote", function() {
    var repo = this.repository;

    return repo.getRemote("origin")
      .then(function(remote) {
        remote.setCallbacks({
          certificateCheck: function() {
            return 1;
          }
        });

        return remote.connect(NodeGit.Enums.DIRECTION.FETCH)
        .then(function() {
          return remote.download(null);
        }).then(function() {
          return remote.disconnect();
        });
      });
  });

  it("can monitor transfer progress while downloading", function() {
    var repo = this.repository;
    var wasCalled = false;

    return repo.getRemote("origin")
      .then(function(remote) {
        remote.checkCert(0);
        remote.setCallbacks({
          transferProgress: function() {
            wasCalled = true;
          }
        });

        remote.connect(NodeGit.Enums.DIRECTION.FETCH);

        return remote.download();
      })
      .then(function() {
        assert.ok(wasCalled);
      });
  });

  it("can fetch from a remote", function() {
    return this.repository.fetch("origin", {
      credentials: function(url, userName) {
        return NodeGit.Cred.sshKeyFromAgent(userName);
      },
      certificateCheck: function() {
        return 1;
      }
    });
  });

  it("can fetch from all remotes", function() {
    // Set a reasonable timeout here for the fetchAll test
    this.timeout(15000);

    return this.repository.fetchAll({
      credentials: function(url, userName) {
        return NodeGit.Cred.sshKeyFromAgent(userName);
      },
      certificateCheck: function() {
        return 1;
      }
    });
  });

});
<commit_msg>Updated to match new API<commit_after>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var local = path.join.bind(path, __dirname);

describe("Remote", function() {
  var NodeGit = require(local("../../"));
  var Repository = require(local("../../lib/repository"));
  var Remote = require(local("../../lib/remote"));

  var reposPath = local("../repos/workdir/.git");
  var url = "https://github.com/nodegit/test";

  function removeOrigins(repository) {
    Remote.delete(repository, "origin1");
    Remote.delete(repository, "origin2");
    Remote.delete(repository, "origin3");
  }

  before(function() {
    var test = this;

    return Repository.open(reposPath)
      .then(function(repository) {
        test.repository = repository;

        return Remote.lookup(repository, "origin");
      })
      .then(function(remote) {
        test.remote = remote;

        return removeOrigins(test.repository);
      });
  });

  after(function() {
    return removeOrigins(this.repository);
  });

  it("can load a remote", function() {
    assert.ok(this.remote instanceof Remote);
  });

  it("can read the remote url", function() {
    assert.equal( this.remote.url().replace(".git", ""), url);
  });

  it("has an empty pushurl by default", function() {
    assert.equal(this.remote.pushurl(), undefined);
  });

  it("can set a remote", function() {
    var repository = this.repository;
    var newRemote;

    return Remote.create(repository, "origin1", url)
      .then(function(remote) {
        newRemote = remote;
        return remote.setPushurl("https://google.com/");
      })
      .then(function() {
        assert(newRemote.pushurl(), "https://google.com/");
      });
  });

  it("can read the remote name", function() {
    assert.equal(this.remote.name(), "origin");
  });

  it("can create and load a new remote", function() {
    var repository = this.repository;

    return Remote.create(repository, "origin2", url)
      .then(function() {
        return Remote.lookup(repository, "origin2");
      })
      .then(function(remote) {
        assert(remote.url(), url);
      });
  });

  it("can delete a remote", function() {
    var repository = this.repository;

    return Remote.create(repository, "origin3", url)
      .then(function(remote) {
        Remote.delete(repository, "origin3");
        return Remote.lookup(repository, "origin3");
      })
      .then(Promise.reject, Promise.resolve);
  });

  it("can download from a remote", function() {
    var repo = this.repository;

    return repo.getRemote("origin")
      .then(function(remote) {
        remote.setCallbacks({
          certificateCheck: function() {
            return 1;
          }
        });

        return remote.connect(NodeGit.Enums.DIRECTION.FETCH)
        .then(function() {
          return remote.download(null);
        }).then(function() {
          return remote.disconnect();
        });
      });
  });

  it("can monitor transfer progress while downloading", function() {
    var repo = this.repository;
    var wasCalled = false;

    return repo.getRemote("origin")
      .then(function(remote) {
        remote.setCallbacks({
          certificateCheck: function() {
            return 0;
          },

          transferProgress: function() {
            wasCalled = true;
          }
        });

        return remote.connect(NodeGit.Enums.DIRECTION.FETCH).then(function() {
          return remote.download(null);
        });
      })
      .then(function() {
        assert.ok(wasCalled);
      });
  });

  it("can fetch from a remote", function() {
    return this.repository.fetch("origin", {
      credentials: function(url, userName) {
        return NodeGit.Cred.sshKeyFromAgent(userName);
      },
      certificateCheck: function() {
        return 1;
      }
    });
  });

  it("can fetch from all remotes", function() {
    // Set a reasonable timeout here for the fetchAll test
    this.timeout(15000);

    return this.repository.fetchAll({
      credentials: function(url, userName) {
        return NodeGit.Cred.sshKeyFromAgent(userName);
      },
      certificateCheck: function() {
        return 1;
      }
    });
  });

});
<|endoftext|>


<commit_before>"use strict";
var webdav = require('../../lib/index.js'),
    request = require('request'),
    stream = require('stream');

module.exports = (test, options, index) => test('source', (isValid, server) =>
{
    isValid = isValid.multiple(2, server);
    const _ = (e, cb) => {
        if(e)
            isValid(false, e);
        else
            cb();
    }

    function expect(value, callback)
    {
        return (e, res, body) => _(e, () => {
            if(value !== body)
                isValid(false, 'The response body (' + body + ') is not equals to the expected value (' + value + ')');
            else
                callback();
        });
    }

    const url = 'http://localhost:' + (options.port + index)

    test('source');
    test('translate');

    function test(headerName)
    {
        let processed = 'processed content';
        let unprocessed = 'unprocessed content';

        server.rootResource.addChild({
            write(targetSource, callback)
            {
                callback(null, new stream.Writable({
                    write: (chunk, encoding, callback) => {
                        if(targetSource)
                            unprocessed = chunk;
                        else
                            processed = chunk;

                        callback(null);
                    }
                }));
            },
            read(targetSource, callback)
            {
                callback(null, new stream.Readable({
                    read: function(size)
                    {
                        this.push(targetSource ? unprocessed : processed);
                        this.push(null);
                    }
                }));
            },
            webName(callback)
            {
                callback(null, 'testFile.txt');
            },
            mimeType(targetSource, callback)
            {
                callback(null, targetSource ? 'text/plain' : 'text/html');
            },
            size(targetSource, callback)
            {
                callback(null, targetSource ? unprocessed.length : processed.length);
            },
            getLocks(callback)
            {
                callback(null, []);
            },
            type(callback)
            {
                callback(null, webdav.ResourceType.File);
            }
        }, (e) => _(e, () => {
            request({
                url: url + '/testFile.txt',
                method: 'GET',
                headers: {
                }
            }, expect(processed, () => {
                request({
                    url: url + '/testFile.txt',
                    method: 'GET',
                    headers: {
                        [headerName]: 'T'
                    }
                }, expect(unprocessed, () => {
                    const old = {
                        processed,
                        unprocessed
                    }
                    request({
                        url: url + '/testFile.txt',
                        method: 'PUT',
                        headers: {
                        },
                        body: processed + 'addon'
                    }, (e, res, body) => _(e, () => {
                        request({
                            url: url + '/testFile.txt',
                            method: 'PUT',
                            headers: {
                                [headerName]: 'T'
                            },
                            body: unprocessed + 'addonX'
                        }, (e, res, body) => _(e, () => {
                            request({
                                url: url + '/testFile.txt',
                                method: 'GET',
                                headers: {
                                }
                            }, expect(old.processed + 'addon', () => {
                                request({
                                    url: url + '/testFile.txt',
                                    method: 'GET',
                                    headers: {
                                        [headerName]: 'T'
                                    }
                                }, expect(old.unprocessed + 'addonX', () => {
                                    isValid(true);
                                }))
                            }))
                        }))
                    }))
                }))
            }))
        }))
    }
})<commit_msg>Improved the tests for the 'source' and 'translate' headers<commit_after>"use strict";
var webdav = require('../../lib/index.js'),
    request = require('request'),
    stream = require('stream');

module.exports = (test, options, index) => test('source', (isValid, server) =>
{
    isValid = isValid.multiple(2, server);
    const _ = (e, cb) => {
        if(e)
            isValid(false, e);
        else
            cb();
    }

    function expect(value, callback)
    {
        return (e, res, body) => _(e, () => {
            if(value !== body)
                isValid(false, 'The response body (' + body + ') is not equals to the expected value (' + value + ')');
            else
                callback();
        });
    }

    const url = 'http://localhost:' + (options.port + index)

    test('source', 'T', 'F');
    test('translate', 'F', 'T');

    function test(headerName, unprocessedHeaderValue, processedHeaderValue)
    {
        let processed = 'processed content';
        let unprocessed = 'unprocessed content';

        server.rootResource.addChild({
            write(targetSource, callback)
            {
                callback(null, new stream.Writable({
                    write: (chunk, encoding, callback) => {
                        if(targetSource)
                            unprocessed = chunk;
                        else
                            processed = chunk;

                        callback(null);
                    }
                }));
            },
            read(targetSource, callback)
            {
                callback(null, new stream.Readable({
                    read: function(size)
                    {
                        this.push(targetSource ? unprocessed : processed);
                        this.push(null);
                    }
                }));
            },
            webName(callback)
            {
                callback(null, 'testFile.txt');
            },
            mimeType(targetSource, callback)
            {
                callback(null, targetSource ? 'text/plain' : 'text/html');
            },
            size(targetSource, callback)
            {
                callback(null, targetSource ? unprocessed.length : processed.length);
            },
            getLocks(callback)
            {
                callback(null, []);
            },
            type(callback)
            {
                callback(null, webdav.ResourceType.File);
            }
        }, (e) => _(e, () => {
            request({
                url: url + '/testFile.txt',
                method: 'GET',
                headers: {
                }
            }, expect(processed, () => {
                request({
                    url: url + '/testFile.txt',
                    method: 'GET',
                    headers: {
                        [headerName]: unprocessedHeaderValue
                    }
                }, expect(unprocessed, () => {
                    const old = {
                        processed,
                        unprocessed
                    }
                    request({
                        url: url + '/testFile.txt',
                        method: 'PUT',
                        headers: {
                            [headerName]: processedHeaderValue
                        },
                        body: processed + 'addon'
                    }, (e, res, body) => _(e, () => {
                        request({
                            url: url + '/testFile.txt',
                            method: 'PUT',
                            headers: {
                                [headerName]: unprocessedHeaderValue
                            },
                            body: unprocessed + 'addonX'
                        }, (e, res, body) => _(e, () => {
                            request({
                                url: url + '/testFile.txt',
                                method: 'GET',
                                headers: {
                                    [headerName]: processedHeaderValue
                                }
                            }, expect(old.processed + 'addon', () => {
                                request({
                                    url: url + '/testFile.txt',
                                    method: 'GET',
                                    headers: {
                                        [headerName]: unprocessedHeaderValue
                                    }
                                }, expect(old.unprocessed + 'addonX', () => {
                                    isValid(true);
                                }))
                            }))
                        }))
                    }))
                }))
            }))
        }))
    }
})<|endoftext|>


<commit_before>(function(__global) {

  var isWorker = typeof window == 'undefined' && typeof self != 'undefined' && typeof importScripts != 'undefined';
  var isBrowser = typeof window != 'undefined' && typeof document != 'undefined';
  var isWindows = typeof process != 'undefined' && !!process.platform.match(/^win/);

  if (!__global.console)
    __global.console = { assert: function() {} };

  // IE8 support
  var indexOf = Array.prototype.indexOf || function(item) {
    for (var i = 0, thisLen = this.length; i < thisLen; i++) {
      if (this[i] === item) {
        return i;
      }
    }
    return -1;
  };

  var defineProperty;
  (function () {
    try {
      if (!!Object.defineProperty({}, 'a', {}))
        defineProperty = Object.defineProperty;
    }
    catch (e) {
      defineProperty = function(obj, prop, opt) {
        try {
          obj[prop] = opt.value || opt.get.call(obj);
        }
        catch(e) {}
      }
    }
  })();

  function addToError(err, msg) {
    var newErr;
    if (err instanceof Error) {
      var newErr = new Error(err.message, err.fileName, err.lineNumber);
      newErr.message = err.message + '\n\t' + msg;
      newErr.stack = err.stack;
    }
    else {
      newErr = err + '\n\t' + msg;
    }

    return newErr;
  }

  function __eval(source, debugName, context) {
    try {
      new Function(source).call(context);
    }
    catch(e) {
      throw addToError(e, 'Evaluating ' + debugName);
    }
  }

  var baseURI;
  // environent baseURI detection
  if (typeof document != 'undefined' && document.getElementsByTagName) {
    baseURI = document.baseURI;

    if (!baseURI) {
      var bases = document.getElementsByTagName('base');
      baseURI = bases[0] && bases[0].href || window.location.href;
    }

    // sanitize out the hash and querystring
    baseURI = baseURI.split('#')[0].split('?')[0];
    baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1);
  }
  else if (typeof process != 'undefined' && process.cwd) {
    baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/';
    if (isWindows)
      baseURI = baseURI.replace(/\\/g, '/');
  }
  else if (typeof location != 'undefined') {
    baseURI = __global.location.href;
  }
  else {
    throw new TypeError('No environment baseURI');
  }

  var URL = typeof __global.URL == 'function' && __global.URL || URLPolyfill;
<commit_msg>Safari URL detection fix (URL is an Object)<commit_after>(function(__global) {

  var isWorker = typeof window == 'undefined' && typeof self != 'undefined' && typeof importScripts != 'undefined';
  var isBrowser = typeof window != 'undefined' && typeof document != 'undefined';
  var isWindows = typeof process != 'undefined' && !!process.platform.match(/^win/);

  if (!__global.console)
    __global.console = { assert: function() {} };

  // IE8 support
  var indexOf = Array.prototype.indexOf || function(item) {
    for (var i = 0, thisLen = this.length; i < thisLen; i++) {
      if (this[i] === item) {
        return i;
      }
    }
    return -1;
  };

  var defineProperty;
  (function () {
    try {
      if (!!Object.defineProperty({}, 'a', {}))
        defineProperty = Object.defineProperty;
    }
    catch (e) {
      defineProperty = function(obj, prop, opt) {
        try {
          obj[prop] = opt.value || opt.get.call(obj);
        }
        catch(e) {}
      }
    }
  })();

  function addToError(err, msg) {
    var newErr;
    if (err instanceof Error) {
      var newErr = new Error(err.message, err.fileName, err.lineNumber);
      newErr.message = err.message + '\n\t' + msg;
      newErr.stack = err.stack;
    }
    else {
      newErr = err + '\n\t' + msg;
    }

    return newErr;
  }

  function __eval(source, debugName, context) {
    try {
      new Function(source).call(context);
    }
    catch(e) {
      throw addToError(e, 'Evaluating ' + debugName);
    }
  }

  var baseURI;
  // environent baseURI detection
  if (typeof document != 'undefined' && document.getElementsByTagName) {
    baseURI = document.baseURI;

    if (!baseURI) {
      var bases = document.getElementsByTagName('base');
      baseURI = bases[0] && bases[0].href || window.location.href;
    }

    // sanitize out the hash and querystring
    baseURI = baseURI.split('#')[0].split('?')[0];
    baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1);
  }
  else if (typeof process != 'undefined' && process.cwd) {
    baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/';
    if (isWindows)
      baseURI = baseURI.replace(/\\/g, '/');
  }
  else if (typeof location != 'undefined') {
    baseURI = __global.location.href;
  }
  else {
    throw new TypeError('No environment baseURI');
  }

  try {
    var URL = typeof __global.URL != 'undefined' && new URL('test:///').protocol == 'test:' && URL;
  }
  catch(e) {}

  URL = URL || URLPolyfill;
<|endoftext|>