<commit_before>var ws = require("nodejs-websocket");

var server = null;
var settings = {
        pingInterval: 30*1000, // ms
        sessionTimeout: 2*60*1000 // ms
};
var errors = {
    msgFailed: "Message construction failed.",
    sendFailed: "Message sending failed.",
    parseFailed: "Message parse failed.",
    malformed: "Message malformed.",
    unknownHeader: "Unknown header."
};

// id: {connections: [], timeout: f}
var sessions = {};

// sessionId: {contact: "", tier: "", region: ""}
var scrims = {};
var tiers = ["Low", "Mid", "High", "High+", "High++"];
var regions = ["SEA", "NA", "EU"];

function message(header, body) {
    var m = {header: header.toUpperCase(), body: body, timestamp: +new Date()};
    try {
        m = JSON.stringify(m);
    } catch (e) {
        return {message: null, error: e};
    } finally {
        return {message: m, error: null};
    }
}

function send(sid, header, body) {
    var m = message(header, body);
    if (m.error) {
        console.log("Error:", errors.msgFailed, m.error);
        return;
    }
    if (!(sid in sessions)) {
        console.log("Error:", errors.sendFailed, "Session with that ID not found.");
        return;
    }
    console.log(sid, "<-", header, body);
    sessions[sid].connections.forEach(function(c) {
        try {
            c.send(m.message);
        } catch(err) {
            console.log("Error:", errors.sendFailed, err);
        }
    });
}

function broadcast(header, body) {
    for (sid in sessions) {
        send(sessions[sid], header, body);
    }
}

function pinger() {
    setInterval(function () {
        broadcast("PING", null)
    }, settings.pingInterval);
}

function merge(conn, sid) {
    if (conn.sessionId === sid) return;
    if (!(sid in sessions)) {
        sessions[sid] = {connections: [conn], timeout: function() {}};
        delete scrims[conn.sessionId];
        delete sessions[conn.sessionId];
        conn.sessionId = sid;
        return;
    }

    delete sessions[conn.sessionId];
    clearTimeout(sessions[sid].timeout);
    sessions[sid].connections.push(conn);

    if (conn.sessionId in scrims) {
        scrims[sid] = scrims[conn.sessionId];
        delete scrims[conn.sessionId];
        update();
    }
    conn.sessionId = sid;
}

function update() {
    broadcast("UPDATE", scrims);
    console.log("Scrims:", scrims);
}

function handle(conn, data) {
    if (!("header" in data) || !("body" in data)) {
        send(conn.sessionId, "ERROR", errors.malformed);
        return;
    }
    data.header = data.header || "";
    data.body = data.body || "";

    switch (data.header.toUpperCase()) {
        case "IDENT":
            var oldSid = parseInt(data.body);
            if (isFinite(oldSid)) {
                console.log("Switch", conn.sessionId, "to", oldSid);
                merge(conn, oldSid);
            }
            break;
        case "SET":
            if (typeof data.body !== "object") {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            if (!("tier" in data.body) || !("region" in data.body) || !("contact" in data.body)) {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            if (tiers.indexOf(data.body.tier) < 0 || regions.indexOf(data.body.region) < 0 || data.body.contact.length > 20) {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            scrims[conn.sessionId] = {contact: data.body.contact, region: data.body.region, tier: data.body.tier};
            update();
            break;
        case "CLEAR":
            delete scrims[conn.sessionId];
            update();
            break;
        case "PONG":
            break;
        case "SESSIONS":
            console.log(Object.keys(sessions));
        default:
            send(sessions[conn.sessionId], "ERROR", errors.unknownHeader);
    }
}

pinger();
server = ws.createServer(function(conn) {
    conn.id = +new Date();
    conn.sessionId = +new Date();
    while (conn.readyState == conn.CONNECTING) {}
    sessions[conn.sessionId] = {connections: [conn], timeout: function() {}};
    console.log(conn.sessionId, "connected.");
    send(conn.sessionId, "IDENT", conn.sessionId);
    update();

    conn.on("text", function(str) {
        var data;
        try {
            data = JSON.parse(str);
        } catch(err) {
            console.log("Error:", errors.parseFailed, err);
            return;
        }
        if (!data) return;
        console.log("Received:", data);
        handle(conn, data);
    });

    conn.on("close", function(code, reason) {
        console.log(conn.sessionId, "disconnected:", code, reason);
        if (conn.sessionId in sessions) {
            for (var i = 0; i < sessions[conn.sessionId].connections.length; i++) {
                var c = sessions[conn.sessionId].connections[i];
                if (c.id === conn.id) {
                    sessions[conn.sessionId].connections.splice(i, 1);
                    break;
                }
            }
            if (sessions[conn.sessionId].connections.length < 1) {
                sessions[conn.sessionId].timeout = setTimeout(function() {
                    delete scrims[conn.sessionId];
                    delete sessions[conn.sessionId];
                    update();
                }, settings.sessionTimeout);
            }
        }
    });
}).listen(process.env.PORT || 8000);
<commit_msg>Small fixes<commit_after>var ws = require("nodejs-websocket");

var server = null;
var settings = {
        pingInterval: 30*1000, // ms
        sessionTimeout: 2*60*1000 // ms
};
var errors = {
    msgFailed: "Message construction failed.",
    sendFailed: "Message sending failed.",
    parseFailed: "Message parse failed.",
    malformed: "Message malformed.",
    unknownHeader: "Unknown header."
};

// id: {connections: [], timeout: f}
var sessions = {};

// sessionId: {contact: "", tier: "", region: ""}
var scrims = {};
var tiers = ["Low", "Mid", "High", "High+", "High++"];
var regions = ["SEA", "NA", "EU"];

function message(header, body) {
    var m = {header: header.toUpperCase(), body: body, timestamp: +new Date()};
    try {
        m = JSON.stringify(m);
    } catch (e) {
        return {message: null, error: e};
    } finally {
        return {message: m, error: null};
    }
}

function send(sid, header, body) {
    var m = message(header, body);
    if (m.error) {
        console.log("Error:", errors.msgFailed, m.error);
        return;
    }
    if (!(sid in sessions)) {
        console.log("Error:", errors.sendFailed, "Session with that ID not found.", sid);
        return;
    }
    console.log(sid, "<-", header, body);
    sessions[sid].connections.forEach(function(c) {
        try {
            c.send(m.message);
        } catch(err) {
            console.log("Error:", errors.sendFailed, err);
        }
    });
}

function broadcast(header, body) {
    for (sid in sessions) {
        send(sessions[sid], header, body);
    }
}

function pinger() {
    setInterval(function () {
        broadcast("PING", null);
    }, settings.pingInterval);
}

function merge(conn, sid) {
    if (conn.sessionId === sid) return;
    if (!(sid in sessions)) {
        sessions[sid] = {connections: [conn], timeout: function() {}};
        delete scrims[conn.sessionId];
        delete sessions[conn.sessionId];
        conn.sessionId = sid;
        return;
    }

    delete sessions[conn.sessionId];
    clearTimeout(sessions[sid].timeout);
    sessions[sid].connections.push(conn);

    if (conn.sessionId in scrims) {
        scrims[sid] = scrims[conn.sessionId];
        delete scrims[conn.sessionId];
        update();
    }
    conn.sessionId = sid;
}

function update() {
    broadcast("UPDATE", scrims);
    console.log("Scrims:", scrims);
}

function handle(conn, data) {
    if (!("header" in data) || !("body" in data)) {
        send(conn.sessionId, "ERROR", errors.malformed);
        return;
    }
    data.header = data.header || "";
    data.body = data.body || "";

    switch (data.header.toUpperCase()) {
        case "IDENT":
            var oldSid = parseInt(data.body);
            if (isFinite(oldSid)) {
                console.log("Switch", conn.sessionId, "to", oldSid);
                merge(conn, oldSid);
            }
            break;
        case "SET":
            if (typeof data.body !== "object") {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            if (!("tier" in data.body) || !("region" in data.body) || !("contact" in data.body)) {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            if (tiers.indexOf(data.body.tier) < 0 || regions.indexOf(data.body.region) < 0 || data.body.contact.length > 20) {
                send(conn.sessionId, "ERROR", errors.malformed);
                break;
            }
            scrims[conn.sessionId] = {contact: data.body.contact, region: data.body.region, tier: data.body.tier};
            update();
            break;
        case "CLEAR":
            delete scrims[conn.sessionId];
            update();
            break;
        case "PONG":
            break;
        case "SESSIONS":
            console.log(Object.keys(sessions));
        default:
            send(sessions[conn.sessionId], "ERROR", errors.unknownHeader);
    }
}

pinger();
server = ws.createServer(function(conn) {
    conn.id = +new Date();
    conn.sessionId = +new Date();
    while (conn.readyState == conn.CONNECTING) {}
    sessions[conn.sessionId] = {connections: [conn], timeout: function() {}};
    console.log(conn.sessionId, "connected.");
    send(conn.sessionId, "IDENT", conn.sessionId);
    update();

    conn.on("text", function(str) {
        var data;
        try {
            data = JSON.parse(str);
        } catch(err) {
            console.log("Error:", errors.parseFailed, err);
            return;
        }
        if (!data) return;
        console.log("Received:", data);
        handle(conn, data);
    });

    conn.on("close", function(code, reason) {
        console.log(conn.id, "disconnected:", code, reason);
        if (conn.sessionId in sessions) {
            for (var i = 0; i < sessions[conn.sessionId].connections.length; i++) {
                var c = sessions[conn.sessionId].connections[i];
                if (c.id === conn.id) {
                    sessions[conn.sessionId].connections.splice(i, 1);
                    break;
                }
            }
            if (sessions[conn.sessionId].connections.length < 1) {
                sessions[conn.sessionId].timeout = setTimeout(function() {
                    delete scrims[conn.sessionId];
                    delete sessions[conn.sessionId];
                    update();
                }, settings.sessionTimeout);
            }
        }
    });
}).listen(process.env.PORT || 8000);
<|endoftext|>


<commit_before>function consumeService(url, service, type) {
  var field_id = "input#" + service + "ServiceLoaded_" + type;
  var loaded = $(field_id).val();

  if (loaded == 'false') {
    if (type == 'xml') {
      consumeXml(url, service, field_id);
    } else if (type == 'json') {
      consumeJson(url, service, field_id);
    } else {
      alert('Unsupported render type ' + type);
    }
  }
}

function consumeJson(url, service, field_id) {
  $('#loading').show();

  var type = 'json';
  var url = 'http://' + location.host + '/verbumdomini/apirest' + url;
  var dataField = service + '_' + type;

  $.getJSON(url, function(data) {
    $('#' + dataField).append('
' + JSON.stringify(data, null, 2) + '
');
    $(field_id).val('true');
  }).done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}

function consumeXml(url, service, field_id) {
  $('#loading').show();

  var type = 'xml';
  var url = 'http://' + location.host + '/verbumdomini/apirest' + url;
  var dataField = service + '_' + type;

  $.get(url, function(data) {
    var xml = vkbeautify.xml(data, 2);
    xml = xml.replace(/</g, '<').replace(/>/g, '>');

    $('#' + dataField).append('
' + xml + '
');
    $(field_id).val('true');
  }, 'text').done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}<commit_msg>Remove static app name from URL.<commit_after>function consumeService(url, service, type) {
  var field_id = "input#" + service + "ServiceLoaded_" + type;
  var loaded = $(field_id).val();

  if (loaded == 'false') {
    if (type == 'xml') {
      consumeXml(url, service, field_id);
    } else if (type == 'json') {
      consumeJson(url, service, field_id);
    } else {
      alert('Unsupported render type ' + type);
    }
  }
}

function consumeJson(path, service, field_id) {
  $('#loading').show();

  var appName = "";

  if (location.pathname.startsWith('/verbumdomini')) {
    appName = '/verbumdomini';
  }

  var type = 'json';
  var url = location.protocol + '//' + location.host + appName + '/apirest' + path;
  var dataField = service + '_' + type;

  $.getJSON(url, function(data) {
    $('#' + dataField).append('
' + JSON.stringify(data, null, 2) + '
');
    $(field_id).val('true');
  }).done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}

function consumeXml(url, service, field_id) {
  $('#loading').show();

  var type = 'xml';
  var url = 'http://' + location.host + '/verbumdomini/apirest' + url;
  var dataField = service + '_' + type;

  $.get(url, function(data) {
    var xml = vkbeautify.xml(data, 2);
    xml = xml.replace(/</g, '<').replace(/>/g, '>');

    $('#' + dataField).append('
' + xml + '
');
    $(field_id).val('true');
  }, 'text').done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}<|endoftext|>


<commit_before>Vue.component('product-list', {
		template :  '' +
								'' +
								'
' +
								'
{{brand_name}}
' +
								'
{{short_description}}
' +
								'
{{actual_price}} TL
' +
								'
{{sale_price}}
' +
								'
' +
								'

' +
								''
})

var productListApp = new Vue({

	el: '#product_list',

	data: {
		products: []
	},

	methods : {

		/**
		 * getProducts() fetches the product data
		 *
		 */
		getProducts : function () {
			var self = this;
			$.ajax({
				url: config.urls.favouriteProducts,
				statusCode : {
					404: function() {
						showError(config.errors['400']);
					},
					500: function() {
						showError(config.errors['500']);
					}
				},
				timeout : 20000,
				beforeSend : function () {
					$(config.el.loader).show();
				},
				success: function(data) {
					var len = (data?data.length:0),
					_data = (data?data:null);
					if (!self.isNull(_data) && len > 0) {
							for (var count = 0; count < len; count++) {
								_data[count][config.json.shortDesc] = self.reduceCharOnShortDesc(_data[count][config.json.shortDesc]);
							}
							self.products = _data;
					} else {
						showError(config.errors.unidentifiedError);
					}
				},
				error : function(xhr, status, error) {
					this.log(xhr, status, error);
					if (status == 'timeout') {
						this.showError(config.errorMessages.timeout);
					}
				},
				complete : function () {
					$(config.el.loader).hide();
				},
				dataType : 'json'
			});
		},

		/**
		 * reduceCharOnShortDesc() returns a limited version of the text delivered as the argument
		 *
		 * @param <String> text
		 *
		 * @return <String>
		 */
		reduceCharOnShortDesc : function (text) {
				return text.substring(0, config.stringBoundry) + config.stringExtension;
		},

		/**
		 * isNull() checks if the argument is null or not
		 *
		 * @param <Object> obj
		 *
		 */
		isNull : function (obj) {
			return (null == obj ? true : false);
		},

		/**
		 * isUndefined() checks if the argument is undefined or not
		 *
		 * @param <Object> o
		 *
		 */
		isUndefined : function (obj) {
			return (undefined == obj ? true ? false);
		},

		/**
		 * showError() arranges error messages
		 *
		 * @param <String> code
		 *
		 */
		showError : function (code){
			$(config.el.loader).hide();
			if (code == config.errors['400']) {
				$(config.el.err).html(config.errorMessages.serverConnectionFailed);
			} else if (code == config.errors['500']) {
				$(config.el.err).html(config.errorMessages.internalServerError);
			} else if (code == 'timeout') {
				$(config.el.err).html(config.errorMessages.timeout);
			} else {
				$(config.el.err).html(config.errorMessages.unidentifiedError);
			}
			$(config.el.err).show();
		},

		/**
		 * log() logs message on the console
		 *
		 * @param <String> msg
		 *
		 */
		log : function (msg) {
			console.log(msg);
		}

	}

});

productListApp.getProducts();<commit_msg>Added comment in app.js file.<commit_after>/*Vue Main App File for Product List :: productListApp*/
var productListApp = new Vue({

	el: '#product_list',

	data: {
		products: []
	},

	methods : {

		/**
		 * getProducts() fetches the product data
		 *
		 */
		getProducts : function () {
			var self = this;
			$.ajax({
				url: config.urls.favouriteProducts,
				statusCode : {
					404: function() {
						showError(config.errors['400']);
					},
					500: function() {
						showError(config.errors['500']);
					}
				},
				timeout : 20000,
				beforeSend : function () {
					$(config.el.loader).show();
				},
				success: function(data) {
					var len = (data?data.length:0),
					_data = (data?data:null);
					if (!self.isNull(_data) && len > 0) {
							for (var count = 0; count < len; count++) {
								_data[count][config.json.shortDesc] = self.reduceCharOnShortDesc(_data[count][config.json.shortDesc]);
							}
							self.products = _data;
					} else {
						showError(config.errors.unidentifiedError);
					}
				},
				error : function(xhr, status, error) {
					this.log(xhr, status, error);
					if (status == 'timeout') {
						this.showError(config.errorMessages.timeout);
					}
				},
				complete : function () {
					$(config.el.loader).hide();
				},
				dataType : 'json'
			});
		},

		/**
		 * reduceCharOnShortDesc() returns a limited version of the text delivered as the argument
		 *
		 * @param <String> text
		 *
		 * @return <String>
		 */
		reduceCharOnShortDesc : function (text) {
				return text.substring(0, config.stringBoundry) + config.stringExtension;
		},

		/**
		 * isNull() checks if the argument is null or not
		 *
		 * @param <Object> obj
		 *
		 */
		isNull : function (obj) {
			return (null == obj ? true : false);
		},

		/**
		 * isUndefined() checks if the argument is undefined or not
		 *
		 * @param <Object> o
		 *
		 */
		isUndefined : function (obj) {
			return (undefined == obj ? true ? false);
		},

		/**
		 * showError() arranges error messages
		 *
		 * @param <String> code
		 *
		 */
		showError : function (code){
			$(config.el.loader).hide();
			if (code == config.errors['400']) {
				$(config.el.err).html(config.errorMessages.serverConnectionFailed);
			} else if (code == config.errors['500']) {
				$(config.el.err).html(config.errorMessages.internalServerError);
			} else if (code == 'timeout') {
				$(config.el.err).html(config.errorMessages.timeout);
			} else {
				$(config.el.err).html(config.errorMessages.unidentifiedError);
			}
			$(config.el.err).show();
		},

		/**
		 * log() logs message on the console
		 *
		 * @param <String> msg
		 *
		 */
		log : function (msg) {
			console.log(msg);
		}

	}

});

productListApp.getProducts();<|endoftext|>


<commit_before>var mockito4js = (function mockito4js() {
    var mockito4js = {};

    mockito4js.doNothing = function () {
        return new MockBuilder(function () {
        });
    };

    mockito4js.doReturn = function (returnValue) {
        return new MockBuilder(function () {
            return returnValue;
        });
    };

    mockito4js.doThrow = function (error) {
        if (typeof error != 'Error') {
            throw new Error('Argument passed to doThrow is not an Error!');
        }

        return new MockBuilder(function () {
            throw error;
        });
    };

    mockito4js.doFire = function (eventName) {
        var event = new MockEvent(eventName);

        function isNoDomElement(target) {
            return !target.nodeType;
        }

        return {
            on: function (target) {
                if (isNoDomElement(target)) {
                    throw new Error('You cannot call doFire on an object that is not a DOM element!');
                }

                return new MockBuilder(function () {
                    event.fire(target);
                });
            }
        };
    };

    mockito4js.spy = function (object) {
        object.invocations = {};
        replaceFunctions(object, object, mockFunction);
        object.isSpy = true;

        return object;
    };

    mockito4js.verify = function (spy, verification) {
        if (spy.isSpy) {
            return new Verifier(spy, verification)
        }

        throw new Error('Verify cannot be called on an object that is not a spy. Use mockito4js.spy() to create a spy object.');
    };

    mockito4js.times = function (numberOfTimes) {
        return new Exactly(numberOfTimes);
    };

    mockito4js.never = function () {
        return new Exactly(0);
    };

    mockito4js.atLeast = function (numberOfTimes) {
        return new AtLeast(numberOfTimes);
    };

    mockito4js.atMost = function (numberOfTimes) {
        return new AtMost(numberOfTimes);
    };

    var Verification = function(invocationCount) {
        this.invocationCount = invocationCount;

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount != this.invocationCount
        };
    };

    Verification.prototype.verify = function(functionName, actualInvocationCount) {
        if (this.numberOfInvocationsNotCorrect(actualInvocationCount)) {
            throw new Error('Number of invocations of "' + functionName + '" does not match the expected amount of ' + this.invocationCount + '.' +
            ' Actual number of invocations is ' + actualInvocationCount);
        }
    };

    var Exactly = function(invocationCount) {
        Verification.call(this, invocationCount);
    };

    Exactly.prototype = Verification.prototype;
    Exactly.prototype.constructor = Exactly;

    var AtLeast = function(invocationCount) {
        Verification.call(this, invocationCount);

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount < this.invocationCount;
        };
    };

    AtLeast.prototype = Verification.prototype;
    AtLeast.prototype.constructor = AtLeast;

    var AtMost = function(invocationCount) {
        Verification.call(this, invocationCount);

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount > this.invocationCount;
        };
    };

    AtMost.prototype = Verification.prototype;
    AtMost.prototype.constructor = AtMost;

    function Verifier(spy, verification) {
        replaceFunctions(this, spy, verifyFunction, {verification: verification});

        function verifyFunction(functionArguments) {
            return function () {
                var invocationCount = getInvocationsWithArguments(functionArguments.object, functionArguments.property, arguments).length;
                functionArguments.additionalArguments.verification.verify(functionArguments.property, invocationCount);
            }
        }

        function getInvocationsWithArguments(object, functionName, expectedArguments) {
            var invocations = [];

            object.invocations[functionName].forEach(function (invocation) {
                if (invocationContainsAllArguments(invocation, expectedArguments)) {
                    invocations.push(invocation);
                }
            });

            return invocations;
        }

        function invocationContainsAllArguments(invocation, expectedArguments) {
            if (expectedArguments.length == 0) {
                return true;
            }

            if (invocation.arguments.length != expectedArguments.length) {
                return false;
            }

            for (var j = 0; j < expectedArguments; j++) {
                var expectedArgument = expectedArguments[j];

                if (invocation.arguments.indexOf(expectedArgument) == -1) {
                    return false;
                }
            }

            return true;
        }
    }

    function MockBuilder(execution) {
        this.when = function (object) {
            if (typeof object == 'function') {
                object = execution;
            } else {
                return new Mock(object, execution);
            }
        }
    }

    function Mock(object, execution) {
        if (object.isSpy) {
            replaceFunctions(this, object, function (functionArguments) {
                functionArguments.functionToReplace = execution;
                return mockFunction(functionArguments);
            });
        } else {
            replaceFunctions(this, object, function (functionArguments) {
                return function() {
                    functionArguments.object[functionArguments.property] = execution;
                    return functionArguments.object[functionArguments.property].apply(this, arguments);
                };
            });
        }
    }

    function MockEvent(name) {
        var event = createEvent(name);

        function createEvent(name) {
            if (document.createEvent) {
                event = document.createEvent("HTMLEvents");
                event.initEvent(name, true, true);
            } else {
                event = document.createEventObject();
                event.eventType = name;
            }

            event.eventName = name;
        }

        this.fire = function (target) {
            if (document.createEvent) {
                target.dispatchEvent(event);
            } else {
                target.fireEvent("on" + event.eventType, event);
            }
        }
    }

    function replaceFunctions(target, object, replacementFunction, additionalArguments) {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                if (typeof object[property] == 'function') {
                    target[property] = replacementFunction({
                        object: object,
                        property: property,
                        functionToReplace: object[property],
                        additionalArguments: additionalArguments
                    });
                }
            }
        }
    }

    function mockFunction(functionArguments) {
        functionArguments.object.invocations[functionArguments.property] = [];

        return function () {
            functionArguments.object.invocations[functionArguments.property].push({arguments: arguments});

            return functionArguments.functionToReplace.apply(this, arguments);
        }
    }

    return mockito4js;
}());<commit_msg>added once to the list of verifiers<commit_after>var mockito4js = (function mockito4js() {
    var mockito4js = {};

    mockito4js.doNothing = function () {
        return new MockBuilder(function () {
        });
    };

    mockito4js.doReturn = function (returnValue) {
        return new MockBuilder(function () {
            return returnValue;
        });
    };

    mockito4js.doThrow = function (error) {
        if (typeof error != 'Error') {
            throw new Error('Argument passed to doThrow is not an Error!');
        }

        return new MockBuilder(function () {
            throw error;
        });
    };

    mockito4js.doFire = function (eventName) {
        var event = new MockEvent(eventName);

        function isNoDomElement(target) {
            return !target.nodeType;
        }

        return {
            on: function (target) {
                if (isNoDomElement(target)) {
                    throw new Error('You cannot call doFire on an object that is not a DOM element!');
                }

                return new MockBuilder(function () {
                    event.fire(target);
                });
            }
        };
    };

    mockito4js.spy = function (object) {
        object.invocations = {};
        replaceFunctions(object, object, mockFunction);
        object.isSpy = true;

        return object;
    };

    mockito4js.verify = function (spy, verification) {
        if (spy.isSpy) {
            return new Verifier(spy, verification)
        }

        throw new Error('Verify cannot be called on an object that is not a spy. Use mockito4js.spy() to create a spy object.');
    };

    mockito4js.times = function (numberOfTimes) {
        return new Exactly(numberOfTimes);
    };

    mockito4js.never = function () {
        return new Exactly(0);
    };

	mockito4js.once = function () {
        return new Exactly(1);
    };

    mockito4js.atLeast = function (numberOfTimes) {
        return new AtLeast(numberOfTimes);
    };

    mockito4js.atMost = function (numberOfTimes) {
        return new AtMost(numberOfTimes);
    };

    var Verification = function(invocationCount) {
        this.invocationCount = invocationCount;

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount != this.invocationCount
        };
    };

    Verification.prototype.verify = function(functionName, actualInvocationCount) {
        if (this.numberOfInvocationsNotCorrect(actualInvocationCount)) {
            throw new Error('Number of invocations of "' + functionName + '" does not match the expected amount of ' + this.invocationCount + '.' +
            ' Actual number of invocations is ' + actualInvocationCount);
        }
    };

    var Exactly = function(invocationCount) {
        Verification.call(this, invocationCount);
    };

    Exactly.prototype = Verification.prototype;
    Exactly.prototype.constructor = Exactly;

    var AtLeast = function(invocationCount) {
        Verification.call(this, invocationCount);

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount < this.invocationCount;
        };
    };

    AtLeast.prototype = Verification.prototype;
    AtLeast.prototype.constructor = AtLeast;

    var AtMost = function(invocationCount) {
        Verification.call(this, invocationCount);

        this.numberOfInvocationsNotCorrect = function(actualInvocationCount) {
            return actualInvocationCount > this.invocationCount;
        };
    };

    AtMost.prototype = Verification.prototype;
    AtMost.prototype.constructor = AtMost;

    function Verifier(spy, verification) {
        replaceFunctions(this, spy, verifyFunction, {verification: verification});

        function verifyFunction(functionArguments) {
            return function () {
                var invocationCount = getInvocationsWithArguments(functionArguments.object, functionArguments.property, arguments).length;
                functionArguments.additionalArguments.verification.verify(functionArguments.property, invocationCount);
            }
        }

        function getInvocationsWithArguments(object, functionName, expectedArguments) {
            var invocations = [];

            object.invocations[functionName].forEach(function (invocation) {
                if (invocationContainsAllArguments(invocation, expectedArguments)) {
                    invocations.push(invocation);
                }
            });

            return invocations;
        }

        function invocationContainsAllArguments(invocation, expectedArguments) {
            if (expectedArguments.length == 0) {
                return true;
            }

            if (invocation.arguments.length != expectedArguments.length) {
                return false;
            }

            for (var j = 0; j < expectedArguments; j++) {
                var expectedArgument = expectedArguments[j];

                if (invocation.arguments.indexOf(expectedArgument) == -1) {
                    return false;
                }
            }

            return true;
        }
    }

    function MockBuilder(execution) {
        this.when = function (object) {
            if (typeof object == 'function') {
                object = execution;
            } else {
                return new Mock(object, execution);
            }
        }
    }

    function Mock(object, execution) {
        if (object.isSpy) {
            replaceFunctions(this, object, function (functionArguments) {
                functionArguments.functionToReplace = execution;
                return mockFunction(functionArguments);
            });
        } else {
            replaceFunctions(this, object, function (functionArguments) {
                return function() {
                    functionArguments.object[functionArguments.property] = execution;
                    return functionArguments.object[functionArguments.property].apply(this, arguments);
                };
            });
        }
    }

    function MockEvent(name) {
        var event = createEvent(name);

        function createEvent(name) {
            if (document.createEvent) {
                event = document.createEvent("HTMLEvents");
                event.initEvent(name, true, true);
            } else {
                event = document.createEventObject();
                event.eventType = name;
            }

            event.eventName = name;
        }

        this.fire = function (target) {
            if (document.createEvent) {
                target.dispatchEvent(event);
            } else {
                target.fireEvent("on" + event.eventType, event);
            }
        }
    }

    function replaceFunctions(target, object, replacementFunction, additionalArguments) {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                if (typeof object[property] == 'function') {
                    target[property] = replacementFunction({
                        object: object,
                        property: property,
                        functionToReplace: object[property],
                        additionalArguments: additionalArguments
                    });
                }
            }
        }
    }

    function mockFunction(functionArguments) {
        functionArguments.object.invocations[functionArguments.property] = [];

        return function () {
            functionArguments.object.invocations[functionArguments.property].push({arguments: arguments});

            return functionArguments.functionToReplace.apply(this, arguments);
        }
    }

    return mockito4js;
}());<|endoftext|>


<commit_before>const path = require('path');

const timeout = 90000;

describe('analytics autolinker', () => {
  let page;

  beforeEach(async () => {
    page = await global.__BROWSER__.newPage();
    await page.goto('http://127.0.0.1:4444/', {
      timeout: 0,
      waitLoad: true,
      waitNetworkIdle: true, // defaults to false
    });

    await page.addScriptTag({
      url: 'https://www.google-analytics.com/analytics.js',
    });
  }, timeout);

  test('autolinker does not modify component URLs already containing an _ga query string', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL w/ existing GA Tracking';
      btn.setAttribute('url', 'https://www.google.com/?_ga=1234');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga=1234');
  });

  test('autolinker updates the URLs of a <bolt-button> with an external url (2nd in the config) + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.brightcove.com');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker tracks the URLs of a <bolt-button> with an external url (2nd in the config) + rendering to the Shadow DOM - even after re-rendering', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    await page.evaluate(() => {
      const btn = document.querySelector('bolt-button');
      btn.setAttribute('url', 'https://www.brightcove.com');
      btn.setAttribute('color', 'secondary');
      return document.body.innerHTML;
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
    expect(currentUrl).toContain('brightcove.com');
  });

  test('autolinker updates the URLs of a <bolt-button> with an external url + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker updates the URLs of <bolt-button>s with external urls + render to the light DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Light DOM Test';
      btn.useShadow = false;
      btn.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker does not track <bolt-button>s with urls not containing domains in the config', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Untracked Domain';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).not.toContain('_ga');
  }, 15000);

  test('autolinker updates the URLs of a <bolt-link> with an external url + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Shadow DOM Test';
      link.style.display = 'inline-block'; // for some strange reason, without any :host styles or this, puppeteer can't seem to find this DOM node to click on
      link.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(link);
    });

    await page.click('bolt-link');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker updates the URLs of a <bolt-link> with an external url + rendering to the light DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Light DOM Test';
      link.useShadow = false;
      link.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(link);
    });

    await page.click('bolt-link');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker does not track <bolt-link>s with urls not containing domains in the config', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Untracked Domain';
      link.style.display = 'inline-block'; // for some strange reason, without any :host styles or this, puppeteer can't seem to find this DOM node to click on
      link.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(link);
    });

    await page.click('bolt-link');
    const currentUrl = await page.url();

    expect(currentUrl).not.toContain('_ga');
  }, 25000);

  test('the correct inline config for specifying autolink domains inside Drupal exists', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(
        __dirname,
        'fixtures/test-analytics.drupal-config.data.js',
      ),
    });

    const config = await page.evaluate(() => {
      return window.drupalSettings.google_analytics.trackCrossDomains;
    });

    expect(config[0]).toBe('pega.com');
  }, 25000);

  test('allow Drupal to configure which domains get configured / tracked by autolink.', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(
        __dirname,
        'fixtures/test-analytics.drupal-config.data.js',
      ),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent =
        'External URL - Normally Untracked But Now Tracked Domain';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    await page.click('bolt-button');
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  }, 25000);
});
<commit_msg>fix: add update autolink click tests to make sure we're waiting for the new page to finish loading before continuing to run checks. https://checklyhq.com/docs/browser-checks/timeouts/#page-waitfornavigation<commit_after>const path = require('path');

const timeout = 90000;

describe('analytics autolinker', () => {
  let page;

  beforeEach(async () => {
    page = await global.__BROWSER__.newPage();
    await page.goto('http://127.0.0.1:4444/', {
      timeout: 0,
      waitLoad: true,
      waitNetworkIdle: true, // defaults to false
    });

    await page.addScriptTag({
      url: 'https://www.google-analytics.com/analytics.js',
    });
  }, timeout);

  test('autolinker does not modify component URLs already containing an _ga query string', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL w/ existing GA Tracking';
      btn.setAttribute('url', 'https://www.google.com/?_ga=1234');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga=1234');
  });

  test('autolinker updates the URLs of a <bolt-button> with an external url (2nd in the config) + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.brightcove.com');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker tracks the URLs of a <bolt-button> with an external url (2nd in the config) + rendering to the Shadow DOM - even after re-rendering', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    await page.evaluate(() => {
      const btn = document.querySelector('bolt-button');
      btn.setAttribute('url', 'https://www.brightcove.com');
      btn.setAttribute('color', 'secondary');
      return document.body.innerHTML;
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
    expect(currentUrl).toContain('brightcove.com');
  });

  test('autolinker updates the URLs of a <bolt-button> with an external url + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Shadow DOM Test';
      btn.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker updates the URLs of <bolt-button>s with external urls + render to the light DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Light DOM Test';
      btn.useShadow = false;
      btn.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker does not track <bolt-button>s with urls not containing domains in the config', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent = 'External URL - Untracked Domain';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).not.toContain('_ga');
  }, 15000);

  test('autolinker updates the URLs of a <bolt-link> with an external url + rendering to the Shadow DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Shadow DOM Test';
      link.style.display = 'inline-block'; // for some strange reason, without any :host styles or this, puppeteer can't seem to find this DOM node to click on
      link.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(link);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-link');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker updates the URLs of a <bolt-link> with an external url + rendering to the light DOM', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Light DOM Test';
      link.useShadow = false;
      link.setAttribute('url', 'https://www.google.com');
      document.body.appendChild(link);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-link');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  });

  test('autolinker does not track <bolt-link>s with urls not containing domains in the config', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(__dirname, 'fixtures/test-analytics-config.data.js'),
    });

    await page.evaluate(() => {
      const link = document.createElement('bolt-link');
      link.textContent = 'External URL - Untracked Domain';
      link.style.display = 'inline-block'; // for some strange reason, without any :host styles or this, puppeteer can't seem to find this DOM node to click on
      link.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(link);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-link');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).not.toContain('_ga');
  }, 25000);

  test('the correct inline config for specifying autolink domains inside Drupal exists', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(
        __dirname,
        'fixtures/test-analytics.drupal-config.data.js',
      ),
    });

    const config = await page.evaluate(() => {
      return window.drupalSettings.google_analytics.trackCrossDomains;
    });

    expect(config[0]).toBe('pega.com');
  }, 25000);

  test('allow Drupal to configure which domains get configured / tracked by autolink.', async function() {
    await page.addScriptTag({
      type: 'module',
      path: path.join(
        __dirname,
        'fixtures/test-analytics.drupal-config.data.js',
      ),
    });

    await page.evaluate(() => {
      const btn = document.createElement('bolt-button');
      btn.textContent =
        'External URL - Normally Untracked But Now Tracked Domain';
      btn.setAttribute('url', 'https://www.pega.com');
      document.body.appendChild(btn);
    });

    const navigationPromise = page.waitForNavigation();
    await page.click('bolt-button');
    await navigationPromise;
    const currentUrl = await page.url();

    expect(currentUrl).toContain('_ga');
  }, 25000);
});
<|endoftext|>


<commit_before>'use strict';

var fs      = require('fs')
  , aritize = require('es5-ext/lib/Function/aritize')
  , curry   = require('es5-ext/lib/Function/curry')
  , invoke  = require('es5-ext/lib/Function/invoke')
  , flatten = require('es5-ext/lib/List/flatten').call
  , a2p     = require('deferred/lib/async-to-promise').call
  , all     = require('deferred/lib/chain/all')
  , concat  = aritize(String.prototype.concat, 1)

  , trim    = require('../path/trim');

module.exports = function readdir (path, callback) {
	path = trim(path);
	a2p(fs.readdir, path).then(function (files) {
		return all(files.map(function (file) {
			var npath = path + '/' + file;
			return a2p(fs.stat, npath).then(function (stats) {
				if (stats.isFile()) {
					return file;
				} else if (stats.isDirectory()) {
					return a2p(readdir, npath).then(invoke('map', concat, file + '/'));
				} else {
					return null;
				}
			});
		}))
		.then(invoke('filter', Boolean))
		.then(flatten)
		.then(curry(callback, null));
	}).end(callback);
};
<commit_msg>Compatibility with es5-ext v0.6<commit_after>'use strict';

var fs      = require('fs')
  , aritize = require('es5-ext/lib/Function/aritize').call
  , curry   = require('es5-ext/lib/Function/curry').call
  , invoke  = require('es5-ext/lib/Function/invoke')
  , flatten = require('es5-ext/lib/List/flatten').call
  , a2p     = require('deferred/lib/async-to-promise').call
  , all     = require('deferred/lib/join/all')
  , concat  = aritize(String.prototype.concat, 1)

  , trim    = require('../path/trim');

module.exports = function readdir (path, callback) {
	path = trim(path);
	a2p(fs.readdir, path).then(function (files) {
		return all(files.map(function (file) {
			var npath = path + '/' + file;
			return a2p(fs.stat, npath).then(function (stats) {
				if (stats.isFile()) {
					return file;
				} else if (stats.isDirectory()) {
					return a2p(readdir, npath).then(invoke('map', concat, file + '/'));
				} else {
					return null;
				}
			});
		}))
		.then(invoke('filter', Boolean))
		.then(flatten)
		.then(curry(callback, null));
	}).end(callback);
};
<|endoftext|>


<commit_before>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2018 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import PropTypes from 'prop-types';
import React from 'react';

import SideNavLayout from './../SideNavLayout';
import * as routes from './../../constants/routes';

const links = [
  {
    id: 'COMPONENTS',
    category: 'Web components',
    sort: true,
    links: [
      { id: 'TEXT', route: routes.TEXT, children: 'Text' },
      { id: 'LINKS', route: routes.LINKS, children: 'Links' },
      { id: 'LISTS', route: routes.LISTS, children: 'Lists' },
      {
        id: 'DESCRIPTION_LISTS',
        route: routes.DESCRIPTION_LISTS,
        children: 'Description Lists',
      },
      { id: 'TABLES', route: routes.TABLES, children: 'Tables' },
      {
        id: 'BLOCKQUOTES',
        route: routes.BLOCKQUOTES,
        children: 'Blockquotes',
      },
      { id: 'CODE', route: routes.CODE, children: 'Code' },
      { id: 'BUTTONS', route: routes.BUTTONS, children: 'Buttons' },
      { id: 'ICONS', route: routes.ICONS, children: 'Icons' },
      { id: 'SPINNERS', route: routes.SPINNERS, children: 'Spinners' },
      { id: 'FORMS', route: routes.FORMS, children: 'Forms' },
      { id: 'CARDS', route: routes.CARDS, children: 'Cards' },
      { id: 'CHIPS', route: routes.CHIPS, children: 'Chips' },
      { id: 'BADGE', route: routes.BADGE, children: 'Badge' },
      { id: 'PANELS', route: routes.PANELS, children: 'Panels' },
      { id: 'IMAGES', route: routes.IMAGES, children: 'Images' },
      {
        id: 'BANNER_ALERTS',
        route: routes.BANNER_ALERTS,
        children: 'Banner alerts',
      },
      {
        id: 'MOBILE_SCROLL_CONTAINER',
        route: routes.MOBILE_SCROLL_CONTAINER,
        children: 'Mobile scroll container',
      },
      { id: 'MODALS', route: routes.MODALS, children: 'Modals' },
      { id: 'AUTOSUGGEST', route: routes.AUTOSUGGEST, children: 'Autosuggest' },
      { id: 'POPOVERS', route: routes.POPOVERS, children: 'Popovers' },
      { id: 'CALENDAR', route: routes.CALENDAR, children: 'Calendar' },
      { id: 'DATEPICKER', route: routes.DATEPICKER, children: 'Datepicker' },
      { id: 'TOOLTIPS', route: routes.TOOLTIPS, children: 'Tooltips' },
      { id: 'ACCORDIONS', route: routes.ACCORDIONS, children: 'Accordions' },
      { id: 'NUDGERS', route: routes.NUDGERS, children: 'Nudgers' },
      { id: 'PROGRESS', route: routes.PROGRESS, children: 'Progress bars' },
      { id: 'TICKETS', route: routes.TICKETS, children: 'Tickets' },
      {
        id: 'HORIZONTAL_NAV',
        route: routes.HORIZONTAL_NAV,
        children: 'Horizontal navigation',
      },
      { id: 'FIELDSETS', route: routes.FIELDSETS, children: 'Fieldsets' },
      {
        id: 'STAR_RATINGS',
        route: routes.STAR_RATING,
        children: 'Star rating',
      },
      { id: 'BAR_CHARTS', route: routes.BARCHARTS, children: 'Bar charts' },
      { id: 'SLIDERS', route: routes.SLIDERS, children: 'Sliders' },
      { id: 'DRAWER', route: routes.DRAWER, children: 'Drawer' },
      { id: 'PAGINATION', route: routes.PAGINATION, children: 'Pagination' },
      { id: 'DIALOGS', route: routes.DIALOGS, children: 'Dialogs' },
      { id: 'CAROUSELS', route: null, children: 'Carousel' },
      { id: 'TOASTS', route: null, children: 'Toast' },
      { id: 'VERTICAL_NAV', route: null, children: 'Vertical navigation' },
      { id: 'OVERFLOW_NAV', route: null, children: 'Overflow navigation' },
      { id: 'BREADCRUMBS', route: null, children: 'Breadcrumbs' },
      { id: 'NUMERICAL_RATING', route: null, children: 'Numerical rating' },
      { id: 'FLIGHT_ITINERARIES', route: null, children: 'Flight itinerary' },
      { id: 'BREAKPOINTS', route: routes.BREAKPOINTS, children: 'Breakpoints' },
      {
        id: 'HORIZONTAL_GRID',
        route: routes.HORIZONTAL_GRID,
        children: 'Horizontal grid',
      },
    ],
  },
  {
    id: 'NATIVE',
    category: 'Native components',
    sort: true,
    links: [
      {
        id: 'NATIVE_BANNER_ALERT',
        route: routes.NATIVE_BANNER_ALERT,
        children: 'Banner alerts',
      },
      { id: 'NATIVE_BUTTON', route: routes.NATIVE_BUTTON, children: 'Button' },
      { id: 'NATIVE_BADGE', route: routes.NATIVE_BADGE, children: 'Badge' },
      // {
      //   id: 'NATIVE_BUTTON_LINK',
      //   route: routes.NATIVE_BUTTON_LINK,
      //   children: 'Button Link',
      // },
      { id: 'NATIVE_CARDS', route: routes.NATIVE_CARDS, children: 'Cards' },
      {
        id: 'NATIVE_HORIZONTAL_NAV',
        route: routes.NATIVE_HORIZONTAL_NAV,
        children: 'Horizontal navigation',
      },
      { id: 'NATIVE_ICONS', route: routes.NATIVE_ICONS, children: 'Icons' },
      {
        id: 'NATIVE_INPUT',
        route: routes.NATIVE_INPUT,
        children: 'Text input',
      },
      {
        id: 'NATIVE_SPINNER',
        route: routes.NATIVE_SPINNER,
        children: 'Spinners',
      },
      {
        id: 'NATIVE_STAR_RATING',
        route: routes.NATIVE_STAR_RATING,
        children: 'Star Rating',
      },
      {
        id: 'NATIVE_SWITCH',
        route: routes.NATIVE_SWITCH,
        children: 'Switches',
      },
      { id: 'NATIVE_TEXT', route: routes.NATIVE_TEXT, children: 'Text' },
      {
        id: 'NATIVE_TOUCHABLE_OVERLAY',
        route: routes.NATIVE_TOUCHABLE_OVERLAY,
        children: 'Touchable Overlay',
      },
      { id: 'NATIVE_BUTTON_LINK', route: null, children: 'Button Link' },
      { id: 'NATIVE_NUDGER', route: null, children: 'Nudger' },
    ],
  },
  {
    id: 'UTILITIES',
    category: 'Utilities',
    sort: true,
    links: [
      { id: 'ALIGNMENT', route: routes.ALIGNMENT, children: 'Alignment' },
      { id: 'THEMING', route: routes.THEMING, children: 'Theming' },
    ],
  },
];

const DocsLayout = ({ children, ...rest }) => (
  <SideNavLayout links={links} {...rest}>
    {children}
  </SideNavLayout>
);

DocsLayout.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]).isRequired,
};

export default DocsLayout;
<commit_msg>[no jira] Enable link buttons page on docs site<commit_after>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2018 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import PropTypes from 'prop-types';
import React from 'react';

import SideNavLayout from './../SideNavLayout';
import * as routes from './../../constants/routes';

const links = [
  {
    id: 'COMPONENTS',
    category: 'Web components',
    sort: true,
    links: [
      { id: 'TEXT', route: routes.TEXT, children: 'Text' },
      { id: 'LINKS', route: routes.LINKS, children: 'Links' },
      { id: 'LISTS', route: routes.LISTS, children: 'Lists' },
      {
        id: 'DESCRIPTION_LISTS',
        route: routes.DESCRIPTION_LISTS,
        children: 'Description Lists',
      },
      { id: 'TABLES', route: routes.TABLES, children: 'Tables' },
      {
        id: 'BLOCKQUOTES',
        route: routes.BLOCKQUOTES,
        children: 'Blockquotes',
      },
      { id: 'CODE', route: routes.CODE, children: 'Code' },
      { id: 'BUTTONS', route: routes.BUTTONS, children: 'Buttons' },
      { id: 'ICONS', route: routes.ICONS, children: 'Icons' },
      { id: 'SPINNERS', route: routes.SPINNERS, children: 'Spinners' },
      { id: 'FORMS', route: routes.FORMS, children: 'Forms' },
      { id: 'CARDS', route: routes.CARDS, children: 'Cards' },
      { id: 'CHIPS', route: routes.CHIPS, children: 'Chips' },
      { id: 'BADGE', route: routes.BADGE, children: 'Badge' },
      { id: 'PANELS', route: routes.PANELS, children: 'Panels' },
      { id: 'IMAGES', route: routes.IMAGES, children: 'Images' },
      {
        id: 'BANNER_ALERTS',
        route: routes.BANNER_ALERTS,
        children: 'Banner alerts',
      },
      {
        id: 'MOBILE_SCROLL_CONTAINER',
        route: routes.MOBILE_SCROLL_CONTAINER,
        children: 'Mobile scroll container',
      },
      { id: 'MODALS', route: routes.MODALS, children: 'Modals' },
      { id: 'AUTOSUGGEST', route: routes.AUTOSUGGEST, children: 'Autosuggest' },
      { id: 'POPOVERS', route: routes.POPOVERS, children: 'Popovers' },
      { id: 'CALENDAR', route: routes.CALENDAR, children: 'Calendar' },
      { id: 'DATEPICKER', route: routes.DATEPICKER, children: 'Datepicker' },
      { id: 'TOOLTIPS', route: routes.TOOLTIPS, children: 'Tooltips' },
      { id: 'ACCORDIONS', route: routes.ACCORDIONS, children: 'Accordions' },
      { id: 'NUDGERS', route: routes.NUDGERS, children: 'Nudgers' },
      { id: 'PROGRESS', route: routes.PROGRESS, children: 'Progress bars' },
      { id: 'TICKETS', route: routes.TICKETS, children: 'Tickets' },
      {
        id: 'HORIZONTAL_NAV',
        route: routes.HORIZONTAL_NAV,
        children: 'Horizontal navigation',
      },
      { id: 'FIELDSETS', route: routes.FIELDSETS, children: 'Fieldsets' },
      {
        id: 'STAR_RATINGS',
        route: routes.STAR_RATING,
        children: 'Star rating',
      },
      { id: 'BAR_CHARTS', route: routes.BARCHARTS, children: 'Bar charts' },
      { id: 'SLIDERS', route: routes.SLIDERS, children: 'Sliders' },
      { id: 'DRAWER', route: routes.DRAWER, children: 'Drawer' },
      { id: 'PAGINATION', route: routes.PAGINATION, children: 'Pagination' },
      { id: 'DIALOGS', route: routes.DIALOGS, children: 'Dialogs' },
      { id: 'CAROUSELS', route: null, children: 'Carousel' },
      { id: 'TOASTS', route: null, children: 'Toast' },
      { id: 'VERTICAL_NAV', route: null, children: 'Vertical navigation' },
      { id: 'OVERFLOW_NAV', route: null, children: 'Overflow navigation' },
      { id: 'BREADCRUMBS', route: null, children: 'Breadcrumbs' },
      { id: 'NUMERICAL_RATING', route: null, children: 'Numerical rating' },
      { id: 'FLIGHT_ITINERARIES', route: null, children: 'Flight itinerary' },
      { id: 'BREAKPOINTS', route: routes.BREAKPOINTS, children: 'Breakpoints' },
      {
        id: 'HORIZONTAL_GRID',
        route: routes.HORIZONTAL_GRID,
        children: 'Horizontal grid',
      },
    ],
  },
  {
    id: 'NATIVE',
    category: 'Native components',
    sort: true,
    links: [
      {
        id: 'NATIVE_BANNER_ALERT',
        route: routes.NATIVE_BANNER_ALERT,
        children: 'Banner alerts',
      },
      { id: 'NATIVE_BUTTON', route: routes.NATIVE_BUTTON, children: 'Button' },
      { id: 'NATIVE_BADGE', route: routes.NATIVE_BADGE, children: 'Badge' },
      {
        id: 'NATIVE_BUTTON_LINK',
        route: routes.NATIVE_BUTTON_LINK,
        children: 'Button Link',
      },
      { id: 'NATIVE_CARDS', route: routes.NATIVE_CARDS, children: 'Cards' },
      {
        id: 'NATIVE_HORIZONTAL_NAV',
        route: routes.NATIVE_HORIZONTAL_NAV,
        children: 'Horizontal navigation',
      },
      { id: 'NATIVE_ICONS', route: routes.NATIVE_ICONS, children: 'Icons' },
      {
        id: 'NATIVE_INPUT',
        route: routes.NATIVE_INPUT,
        children: 'Text input',
      },
      {
        id: 'NATIVE_SPINNER',
        route: routes.NATIVE_SPINNER,
        children: 'Spinners',
      },
      {
        id: 'NATIVE_STAR_RATING',
        route: routes.NATIVE_STAR_RATING,
        children: 'Star Rating',
      },
      {
        id: 'NATIVE_SWITCH',
        route: routes.NATIVE_SWITCH,
        children: 'Switches',
      },
      { id: 'NATIVE_TEXT', route: routes.NATIVE_TEXT, children: 'Text' },
      {
        id: 'NATIVE_TOUCHABLE_OVERLAY',
        route: routes.NATIVE_TOUCHABLE_OVERLAY,
        children: 'Touchable Overlay',
      },
      { id: 'NATIVE_BUTTON_LINK', route: null, children: 'Button Link' },
      { id: 'NATIVE_NUDGER', route: null, children: 'Nudger' },
    ],
  },
  {
    id: 'UTILITIES',
    category: 'Utilities',
    sort: true,
    links: [
      { id: 'ALIGNMENT', route: routes.ALIGNMENT, children: 'Alignment' },
      { id: 'THEMING', route: routes.THEMING, children: 'Theming' },
    ],
  },
];

const DocsLayout = ({ children, ...rest }) => (
  <SideNavLayout links={links} {...rest}>
    {children}
  </SideNavLayout>
);

DocsLayout.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]).isRequired,
};

export default DocsLayout;
<|endoftext|>


<commit_before>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2016-2019 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React from 'react';
import BpkLink from 'bpk-component-link';
import BpkRouterLink from 'bpk-component-router-link';
import { BpkList, BpkListItem } from 'bpk-component-list';
import BpkBlockquote from 'bpk-component-blockquote';
import webReadme from 'bpk-theming/README.md';

import nativeReadme from '../../../../../backpack-react-native/packages/react-native-bpk-theming/README.md';
import Paragraph from '../../components/Paragraph';
import IntroBlurb from '../../components/IntroBlurb';
import Android from '../AndroidThemingPage';
import IOS from '../IOSThemingPage';
import DocsPageBuilder from '../../components/DocsPageBuilder';
import DocsPageWrapper from '../../components/DocsPageWrapper';
import {
  ACCORDION,
  BARCHART,
  BLOCKQUOTE,
  BREADCRUMB,
  BUTTON,
  CALENDAR,
  DATEPICKER,
  DRAWER,
  FLAT_LIST,
  HORIZONTAL_NAV,
  LINK,
  MODAL,
  NAVIGATION_BAR,
  NUDGER,
  PAGINATION,
  POPOVER,
  PROGRESS,
  SCROLLABLE_CALENDAR,
  SECTION_LIST,
  SLIDER,
  SPINNER,
  SWITCH,
} from '../../constants/routes';

const CONTEXT_API_URL = 'https://reactjs.org/docs/context.html';
const CSS_VARIABLES_URL =
  'https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables';

const nativeBlurb = [
  <Paragraph>The following native components are themeable:</Paragraph>,
  <BpkList>
    <BpkListItem>
      <BpkRouterLink to={BUTTON}>Button</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={FLAT_LIST}>Flat list</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={HORIZONTAL_NAV}>Horizontal navigation</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={LINK}>Link</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NAVIGATION_BAR}>Navigation bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NUDGER}>Nudger</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PROGRESS}>Progress</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SECTION_LIST}>Section list</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SPINNER}>Spinner</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SWITCH}>Switch</BpkRouterLink>
    </BpkListItem>
  </BpkList>,
];

const webBlurb = [
  <Paragraph>The following web components are themeable:</Paragraph>,
  <BpkList>
    <BpkListItem>
      <BpkRouterLink to={ACCORDION}>Accordion</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BARCHART}>Bar chart</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BLOCKQUOTE}>Blockquote</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BREADCRUMB}>Breadcrumb</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BUTTON}>Button</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={CALENDAR}>Calendar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={DATEPICKER}>Datepicker</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={DRAWER}>Drawer</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={HORIZONTAL_NAV}>Horizontal navigation</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={LINK}>Link</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={MODAL}>Modal</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NAVIGATION_BAR}>Navigation bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NUDGER}>Nudgers</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PAGINATION}>Pagination</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={POPOVER}>Popover</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PROGRESS}>Progress bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SCROLLABLE_CALENDAR}>
        Scrollable calendar
      </BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SLIDER}>Slider</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SPINNER}>Spinner</BpkRouterLink>
    </BpkListItem>
  </BpkList>,
  <BpkBlockquote>
    Note: Backpack's theming is based on
    <BpkLink href={CSS_VARIABLES_URL} blank>
      CSS Variables
    </BpkLink>
    and thus will not be supported in some browsers. In these cases Backpack
    components will gracefully degrade to the default Skyscanner theme. For an
    overview of this check
    <BpkLink href="https://caniuse.com/#feat=css-variables" blank>
      caniuse
    </BpkLink>
    .
  </BpkBlockquote>,
];

const blurb = [
  <IntroBlurb>
    All Backpack components have full theming support through through the theme
    provider component. In the render tree, all themeable components will have
    access to the provided theme, even when they are multiple levels deep.
    variables are used.
  </IntroBlurb>,
  <Paragraph>
    In React Native, this is achieved using React's{' '}
    <BpkLink href={CONTEXT_API_URL} blank>
      context API
    </BpkLink>
    . On the web,{' '}
    <BpkLink href={CSS_VARIABLES_URL} blank>
      CSS variables
    </BpkLink>{' '}
    are used. Each themeable component lists the theme attributes it requires in
    its readme.
  </Paragraph>,
];

const WebThemingPage = ({ ...rest }) => (
  <DocsPageBuilder
    blurb={webBlurb}
    showMenu={false}
    readme={webReadme}
    {...rest}
  />
);

const NativeThemingPage = ({ ...rest }) => (
  <DocsPageBuilder
    blurb={nativeBlurb}
    showMenu={false}
    readme={nativeReadme}
    {...rest}
  />
);

const ThemingPage = () => (
  <DocsPageWrapper
    title="Theming"
    blurb={blurb}
    webSubpage={<WebThemingPage wrapped />}
    nativeSubpage={<NativeThemingPage wrapped />}
    iosSubpage={<IOS wrapped />}
    androidSubpage={<Android wrapped />}
  />
);

export default ThemingPage;
<commit_msg>Add calendar to RN theming list<commit_after>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2016-2019 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React from 'react';
import BpkLink from 'bpk-component-link';
import BpkRouterLink from 'bpk-component-router-link';
import { BpkList, BpkListItem } from 'bpk-component-list';
import BpkBlockquote from 'bpk-component-blockquote';
import webReadme from 'bpk-theming/README.md';

import nativeReadme from '../../../../../backpack-react-native/packages/react-native-bpk-theming/README.md';
import Paragraph from '../../components/Paragraph';
import IntroBlurb from '../../components/IntroBlurb';
import Android from '../AndroidThemingPage';
import IOS from '../IOSThemingPage';
import DocsPageBuilder from '../../components/DocsPageBuilder';
import DocsPageWrapper from '../../components/DocsPageWrapper';
import {
  ACCORDION,
  BARCHART,
  BLOCKQUOTE,
  BREADCRUMB,
  BUTTON,
  CALENDAR,
  DATEPICKER,
  DRAWER,
  FLAT_LIST,
  HORIZONTAL_NAV,
  LINK,
  MODAL,
  NAVIGATION_BAR,
  NUDGER,
  PAGINATION,
  POPOVER,
  PROGRESS,
  SCROLLABLE_CALENDAR,
  SECTION_LIST,
  SLIDER,
  SPINNER,
  SWITCH,
} from '../../constants/routes';

const CONTEXT_API_URL = 'https://reactjs.org/docs/context.html';
const CSS_VARIABLES_URL =
  'https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables';

const nativeBlurb = [
  <Paragraph>The following native components are themeable:</Paragraph>,
  <BpkList>
    <BpkListItem>
      <BpkRouterLink to={BUTTON}>Button</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={CALENDAR}>Calendar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={FLAT_LIST}>Flat list</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={HORIZONTAL_NAV}>Horizontal navigation</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={LINK}>Link</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NAVIGATION_BAR}>Navigation bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NUDGER}>Nudger</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PROGRESS}>Progress</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SECTION_LIST}>Section list</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SPINNER}>Spinner</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SWITCH}>Switch</BpkRouterLink>
    </BpkListItem>
  </BpkList>,
];

const webBlurb = [
  <Paragraph>The following web components are themeable:</Paragraph>,
  <BpkList>
    <BpkListItem>
      <BpkRouterLink to={ACCORDION}>Accordion</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BARCHART}>Bar chart</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BLOCKQUOTE}>Blockquote</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BREADCRUMB}>Breadcrumb</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={BUTTON}>Button</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={CALENDAR}>Calendar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={DATEPICKER}>Datepicker</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={DRAWER}>Drawer</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={HORIZONTAL_NAV}>Horizontal navigation</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={LINK}>Link</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={MODAL}>Modal</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NAVIGATION_BAR}>Navigation bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={NUDGER}>Nudgers</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PAGINATION}>Pagination</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={POPOVER}>Popover</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={PROGRESS}>Progress bar</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SCROLLABLE_CALENDAR}>
        Scrollable calendar
      </BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SLIDER}>Slider</BpkRouterLink>
    </BpkListItem>
    <BpkListItem>
      <BpkRouterLink to={SPINNER}>Spinner</BpkRouterLink>
    </BpkListItem>
  </BpkList>,
  <BpkBlockquote>
    Note: Backpack's theming is based on
    <BpkLink href={CSS_VARIABLES_URL} blank>
      CSS Variables
    </BpkLink>
    and thus will not be supported in some browsers. In these cases Backpack
    components will gracefully degrade to the default Skyscanner theme. For an
    overview of this check
    <BpkLink href="https://caniuse.com/#feat=css-variables" blank>
      caniuse
    </BpkLink>
    .
  </BpkBlockquote>,
];

const blurb = [
  <IntroBlurb>
    All Backpack components have full theming support through through the theme
    provider component. In the render tree, all themeable components will have
    access to the provided theme, even when they are multiple levels deep.
    variables are used.
  </IntroBlurb>,
  <Paragraph>
    In React Native, this is achieved using React's{' '}
    <BpkLink href={CONTEXT_API_URL} blank>
      context API
    </BpkLink>
    . On the web,{' '}
    <BpkLink href={CSS_VARIABLES_URL} blank>
      CSS variables
    </BpkLink>{' '}
    are used. Each themeable component lists the theme attributes it requires in
    its readme.
  </Paragraph>,
];

const WebThemingPage = ({ ...rest }) => (
  <DocsPageBuilder
    blurb={webBlurb}
    showMenu={false}
    readme={webReadme}
    {...rest}
  />
);

const NativeThemingPage = ({ ...rest }) => (
  <DocsPageBuilder
    blurb={nativeBlurb}
    showMenu={false}
    readme={nativeReadme}
    {...rest}
  />
);

const ThemingPage = () => (
  <DocsPageWrapper
    title="Theming"
    blurb={blurb}
    webSubpage={<WebThemingPage wrapped />}
    nativeSubpage={<NativeThemingPage wrapped />}
    iosSubpage={<IOS wrapped />}
    androidSubpage={<Android wrapped />}
  />
);

export default ThemingPage;
<|endoftext|>


<commit_before>var ecstatic = require('ecstatic')
  , server = require('http').createServer(
      ecstatic({ root: __dirname + '/visual' })
  ).listen(9999)
  , websocket = require('websocket-stream')
  , WebSocketServer = require('ws').Server
  , emitIO = require('emit.io')()
  , wss =  new WebSocketServer({server: server})
  , EventEmitter = require('events').EventEmitter
  , MuxDemux = require('mux-demux')
var Game = require('./lib/game')
var util = require('./lib/util')
var UserMoves = require('./user/moves')
var UserDistance = require('./user/distance')
var UserAttack = require('./user/attack')

console.log('Listening on :9999');

wss.on('connection', function(ws) {

  var wstream = websocket(ws)
    , mx = MuxDemux(router)

  mx.on('error', function () {
    wstream.destroy()
  })
  wstream.on('error', function () {
    mx.destroy()
  })

  wstream.pipe(mx).pipe(wstream)
})

function router (stream) {

  var gridSize = [20,20]

  var board = Game.newBoard({x:gridSize[0], y:gridSize[1]})

  emitIO(stream, board)
  // link emitter to outgoing stream
  var emitStream = emitIO(board)
  emitStream.pipe(stream)

    //  console.log('grid ready')

  board.emit('init', gridSize)
  board.on('ready', function () {

    //board.init([20,20])

    var saul = Game.newUnit('Person', {name: 'saul'})
    var sally = Game.newUnit('Person', {name: 'sally'})

    saul.joinBoard(board, {x:4, y:5})

    saul.on('damage', function () {
      console.log('better call saul!', saul.getHealth())
    })

    saul.on('terminated', function () {
    console.log("ah fuck, i'm dead   --saul")
    })

    // pipe sally into control stream
    sally.joinBoard(board)

    util.extend(sally, UserMoves)
    util.extend(sally, UserDistance)
    util.extend(sally, UserAttack)

    var target = sally.visibleUnits()[0]

    sally.moveToAttack(target, 1)

    sally.on('inRange', function () {
      console.log('sally in Range')
      sally.attackWhileInRange(target, 1)
    })

    sally.on('hit', function (damage) {
      console.log('sally landed blow for', damage, 'damage')
    })

    sally.on('target-destroyed', function (target) {
//      sally.store(target.getLoot())
    })

    saul.on('move', function (status) {
      console.log("saul moved to", saul.getLocation())
    })

  })

}
<commit_msg>agwergads<commit_after>var ecstatic = require('ecstatic')
  , server = require('http').createServer(
      ecstatic({ root: __dirname + '/visual' })
  ).listen(9999)
  , websocket = require('websocket-stream')
  , WebSocketServer = require('ws').Server
  , emitIO = require('emit.io')()
  , wss =  new WebSocketServer({server: server})
  , EventEmitter = require('events').EventEmitter
  , MuxDemux = require('mux-demux')
var Game = require('./lib/game')
var util = require('./lib/util')
var UserMoves = require('./user/moves')
var UserDistance = require('./user/distance')
var UserAttack = require('./user/attack')

console.log('Listening on :9999');

wss.on('connection', function(ws) {

  var wstream = websocket(ws)
    , mx = MuxDemux(router)

  mx.on('error', function () {
    wstream.destroy()
  })
  wstream.on('error', function () {
    mx.destroy()
  })

  wstream.pipe(mx).pipe(wstream)
})

function router (stream) {

  var gridSize = [20,20]

  var board = Game.newBoard({x:gridSize[0], y:gridSize[1]})

  emitIO(stream, board)
  // link emitter to outgoing stream
  var emitStream = emitIO(board)
  emitStream.pipe(stream)

    //  console.log('grid ready')

  board.emit('init', gridSize)
  board.on('ready', function () {

    //board.init([20,20])

    var saul = Game.newUnit('Person', {name: 'saul'})
    var sally = Game.newUnit('Person', {name: 'sally'})

    saul.joinBoard(board, {x:4, y:5})

    // pipe sally into control stream
    sally.joinBoard(board)

    util.extend(sally, UserMoves)
    util.extend(sally, UserDistance)
    util.extend(sally, UserAttack)

    var target = sally.visibleUnits()[0]

    sally.moveToAttack(target, 1)

    sally.on('inRange', function () {
      console.log('sally in Range')
      sally.attackWhileInRange(target, 1)
    })

    sally.on('hit', function (damage) {
      console.log('sally landed blow for', damage, 'damage')
    })

    sally.on('target-destroyed', function (target) {
//      sally.store(target.getLoot())
    })

    saul.on('damage', function () {
      console.log('better call saul!', saul.getHealth())
    })

    saul.on('terminated', function () {
    console.log("ah fuck, i'm dead   --saul")
    })

    saul.on('move', function (status) {
      console.log("saul moved to", saul.getLocation())
    })

  })

}
<|endoftext|>


<commit_before>// Copyright 2011 WebDriver committers
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Atoms for frame handling.
 *
 */

goog.provide('bot.frame');

goog.require('bot.locators');
goog.require('goog.array');
goog.require('goog.dom');

/**
 * @return {!Window} The top window.
 */
bot.frame.defaultContent = function() {
  return bot.getWindow().top;
};

/**
 * @return {!Element} The currently active element.
 */
bot.frame.activeElement = function() {
  return document.activeElement || document.body;
};

/**
 * Returns a reference to the window object corresponding to the given element.
 * Note that the element must be a frame or an iframe.
 *
 * @param {!Element} element The iframe or frame element.
 * @return {Window} The window reference for the given iframe or frame element.
 */
bot.frame.getFrameWindow = function(element) {
  if (/^i?frame$/i.test(element.tagName)) {
    var frame = /** @type {HTMLFrameElement|HTMLIFrameElement} */ element;
    return goog.dom.getFrameContentWindow(frame);
  }
  throw new bot.Error(bot.ErrorCode.NO_SUCH_FRAME,
      "The given element isn't a frame or an iframe.");
};

/**
 * Looks for a frame by its name or id (preferring name over id)
 * under the given root. If no frame was found, we look for an
 * iframe by name or id.
 *
 * @param {string} nameOrId The frame's name or the frame's id.
 * @param {!Window=} opt_root The window to perform the search under.
 *     Defaults to {@code bot.getWindow()}.
 * @return {Window} The window if found, null otherwise.
 */
bot.frame.findFrameByNameOrId = function(nameOrId, opt_root) {
  var domWindow = opt_root || bot.getWindow();

  // Lookup frame by name
  var frame = domWindow.frames[nameOrId];
  if (frame) {
    // This is needed because Safari 4 returns
    // an HTMLFrameElement instead of a Window object.
    if (frame.document) {
      return frame;
    } else {
      return goog.dom.getFrameContentWindow(frame);
    }
  }

  // Lookup frame by id
  var isFrame = function(element) {
    return bot.dom.isElement(element, goog.dom.TagName.FRAME) ||
        bot.dom.isElement(element, goog.dom.TagName.IFRAME);
  }
  var elements = bot.locators.findElements({id: nameOrId},
      domWindow.document);
  for (var i = 0; i < elements.length; i++) {
    if (isFrame(elements[i])) {
      return goog.dom.getFrameContentWindow(elements[i]);
    }
  }
  return null;
};

/**
 * Looks for a frame by its index under the given root.
 *
 * @param {number} index The frame's index.
 * @param {!Window=} opt_root The window to perform
 *     the search under. Defaults to {@code bot.getWindow()}.
 * @return {Window} The frame if found, null otherwise.
 */
bot.frame.findFrameByIndex = function(index, opt_root) {
  var domWindow = opt_root || bot.getWindow();
  return domWindow.frames[index] || null;
};

/**
 * Gets the index of a frame in the given window. Note that the element must
 * be a frame or an iframe.
 *
 * @param {Element} element The iframe or frame element.
 * @param {!Window=} opt_root The window to perform
 *     the search under. Defaults to {@code bot.getWindow()}.
 * @return {number} The index of the frame if found, null otherwise.
 */
bot.frame.getFrameIndex = function(element, opt_root) {
  var domWindow = opt_root || bot.getWindow();

  if (element.nodeType != 1 || !/^i?frame$/i.test(element.tagName)) {
    return null;
  }
  for (var i = 0; i < domWindow.frames.length; i++) {
    if (element.contentWindow == domWindow.frames[i]) {
      return i;
    }
  }
  return null;
};
<commit_msg>StuartKnightley: Make corrections to r13804 based on SimonStewart's comments<commit_after>// Copyright 2011 WebDriver committers
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Atoms for frame handling.
 *
 */

goog.provide('bot.frame');

goog.require('bot.locators');
goog.require('goog.array');
goog.require('goog.dom');

/**
 * @return {!Window} The top window.
 */
bot.frame.defaultContent = function() {
  return bot.getWindow().top;
};

/**
 * @return {!Element} The currently active element.
 */
bot.frame.activeElement = function() {
  return document.activeElement || document.body;
};

/**
 * Returns a reference to the window object corresponding to the given element.
 * Note that the element must be a frame or an iframe.
 *
 * @param {!HTMLIFrameElement|!HTMLFrameElement} element The iframe or frame
 *     element.
 * @return {Window} The window reference for the given iframe or frame element.
 */
bot.frame.getFrameWindow = function(element) {
  if (/^i?frame$/i.test(element.tagName)) {
    var frame = /** @type {HTMLFrameElement|HTMLIFrameElement} */ element;
    return goog.dom.getFrameContentWindow(frame);
  }
  throw new bot.Error(bot.ErrorCode.NO_SUCH_FRAME,
      "The given element isn't a frame or an iframe.");
};

/**
 * Looks for a frame by its name or id (preferring name over id)
 * under the given root. If no frame was found, we look for an
 * iframe by name or id.
 *
 * @param {(string|number)} nameOrId The frame's name or the frame's id.
 * @param {Window} opt_root The window to perform the search under.
 *     Defaults to {@code bot.getWindow()}.
 * @return {Window} The window if found, null otherwise.
 */
bot.frame.findFrameByNameOrId = function(nameOrId, opt_root) {
  var domWindow = opt_root || bot.getWindow();

  // Lookup frame by name
  var frame = domWindow.frames[nameOrId];
  if (frame) {
    // This is needed because Safari 4 returns
    // an HTMLFrameElement instead of a Window object.
    if (frame.document) {
      return frame;
    } else {
      return goog.dom.getFrameContentWindow(frame);
    }
  }

  // Lookup frame by id
  var isFrame = function(element) {
    return bot.dom.isElement(element, goog.dom.TagName.FRAME) ||
        bot.dom.isElement(element, goog.dom.TagName.IFRAME);
  }
  var elements = bot.locators.findElements({id: nameOrId},
      domWindow.document);
  for (var i = 0; i < elements.length; i++) {
    if (isFrame(elements[i])) {
      return goog.dom.getFrameContentWindow(elements[i]);
    }
  }
  return null;
};

/**
 * Looks for a frame by its index under the given root.
 *
 * @param {number} index The frame's index.
 * @param {Window} opt_root The window to perform
 *     the search under. Defaults to {@code bot.getWindow()}.
 * @return {Window} The frame if found, null otherwise.
 */
bot.frame.findFrameByIndex = function(index, opt_root) {
  var domWindow = opt_root || bot.getWindow();
  return domWindow.frames[index] || null;
};

/**
 * Gets the index of a frame in the given window. Note that the element must
 * be a frame or an iframe.
 *
 * @param {!HTMLIFrameElement|!HTMLFrameElement} element The iframe or frame
 *     element.
 * @param {Window} opt_root The window to perform
 *     the search under. Defaults to {@code bot.getWindow()}.
 * @return {number=} The index of the frame if found, null otherwise.
 */
bot.frame.getFrameIndex = function(element, opt_root) {
  var domWindow = opt_root || bot.getWindow();

  if (!bot.dom.isElement(element, goog.dom.TagName.FRAME) &&
      !bot.dom.isElement(element, goog.dom.TagName.IFRAME)
  ) {
    return null;
  }
  for (var i = 0; i < domWindow.frames.length; i++) {
    if (element.contentWindow == domWindow.frames[i]) {
      return i;
    }
  }
  return null;
};
<|endoftext|>


<commit_before>var SERVER = {

	_waitingForResponse: null,
	_result: null,

	performOnServer : function (classname, selector, args) {
		// Object >> perform: selector withArguments: argArray
		CONNECTION.send("INVOKE " + classname + "." + selector + "." + args);
		SERVER._waitingForResponse = true;
		while(_waitingForResponse) {
			// busy wait
		}
		return SERVER._result;
	},

	callback : function(result) {
		// response handled through comet or sockets will
		// contain as result a function call like "callback(result)"
		SERVER._result = result;
		SERVER._waitingForResponse = false;
	}

}
<commit_msg>Server.js: PerformOnServer takes a single string argument at most instead of some array. So far only class methods can be invoked.<commit_after>var SERVER = {

	_waitingForResponse: null,
	_result: null,

	performOnServer : function (classname, selector, stringArgument) {
		// Object >> perform: selector withArguments: argArray
		CONNECTION.send("INVOKE: " + classname + "." + selector + "." + stringArgument);
		SERVER._waitingForResponse = true;
		while(_waitingForResponse) {
			// busy wait
		}
		return SERVER._result;
	},

	callback : function(result) {
		// response handled through comet or sockets will
		// contain as result a function call like "callback(result)"
		SERVER._result = result;
		SERVER._waitingForResponse = false;
	}

}
<|endoftext|>