<commit_before>define('/style/js/biz/rules.js', function(require, exports, module) {
	var hostsData, inited, values;
	var newHostsList = $('#newHostsList');
	var glyphiconOk = '';

	var hostsEditor = CodeMirror($('#hostsEditor')[0], {
    	mode: 'text/whistle'
  	});

	var themeOptions = $('#themeOptions').change(function() {
		var theme = this.value;
		$.post('/cgi-bin/hosts/set-theme',{theme: theme});
		hostsEditor.setOption('theme', theme);
	});

	var fontSizeOptions = $('#fontSizeOptions').change(function() {
        var fontSize = this.value;
        $.post('/cgi-bin/hosts/set-font-size',{fontSize: fontSize});
        hostsEditor.getWrapperElement().style.fontSize = fontSize;
        hostsEditor.refresh();
	});

	var showLineNumbers = $('#showLineNumbers').change(function() {
		$.post('/cgi-bin/hosts/show-line-numbers',{showLineNumbers: this.checked ? 1 : 0});
		hostsEditor.setOption('lineNumbers', this.checked);
	});

	function initActionBar(data) {
		themeOptions.val(data.theme || 'cobalt').trigger('change');
		fontSizeOptions.val(data.fontSize || '16px').trigger('change');
		showLineNumbers.prop('checked', data.showLineNumbers == true);
		showLineNumbers.trigger('change');
	}

	var body = $(document.body).on('click', '.hosts-list .list-group-item', function() {
		var self = $(this);
		if (self.hasClass('create-hosts')) {
			return;
		}

		var hostsList = self.closest('.hosts-list');
		var activeItem = hostsList.find('.list-group-item.active').removeClass('active');
		var hostsName = activeItem.text();

		if (activeItem.hasClass('public-hosts')) {
			hostsData.publicHosts = hostsEditor.getValue();
		} else {
			hostsData.hostsData[hostsName] = hostsEditor.getValue();
		}

		self.addClass('active');

		var hostsNav = $('#hostsNav');
		hostsName = self.text();

		hostsNav.find('.hosts-title').text(hostsName);

		if (self.hasClass('public-hosts')) {
			hostsNav.find('.remove-hosts').hide();
			hostsNav.find('.enable-public-hosts').show();
			hostsEditor.setValue(hostsData.publicHosts || '');
		} else {
			hostsNav.find('.remove-hosts').show();
			hostsNav.find('.enable-public-hosts').hide();
			hostsEditor.setValue(hostsData.hostsData[hostsName] || '');
		}
	}).on('dblclick', '.hosts-list .list-group-item', function() {
		$('.apply-hosts').trigger('click');
	});

	body.on('click', '.enable-public-hosts', function() {
		var enable = $('#enablePublicHosts').prop('checked');
		var glyphicon = $('#publicHosts').find('.glyphicon-ok');
		enable ? glyphicon.show() : glyphicon.hide();
		updatePublicHostsState();
		$.post('/cgi-bin/hosts/enable',{enable: enable ? 1 : 0});
	});

	function updatePublicHostsState() {
		var enable = $('#enablePublicHosts').prop('checked');
		$('#publicHosts').css('color', enable ? '' : '#ccc')
		.attr('title', enable ? '先到自定义规则查找，如果没有匹配的再查找Public' : '公用环境已禁用');
	}

	body.on('click', '.remove-hosts', function() {
		if (confirm("确认删除？"))  {
			var hosts = newHostsList.find('.active');
			var name = hosts.text();

			$.post('/cgi-bin/hosts/remove',{name: name});
			var next = hosts.next();
			if (!next.length) {
				next = hosts.prev();
			}
			(next.length ? next : $('#publicHosts')).trigger('click');
			hosts.remove();
			delete hostsData.hostsData[name];
			updateCreateHostsBtnState();
		}

	});

	$('#hostsEditor').keyup(function(e) {
		if ((e.ctrlKey || e.metaKey)
				&& (e.keyCode == 13 || e.keyCode == 83)) {
			$('.apply-hosts').trigger('click');
		}
	}).keydown(function(e) {
		if (e.ctrlKey && e.keyCode == 83) {
			e.preventDefault();
			return false;
		}
	});

	body.on('click', '.apply-hosts,.confirm-hosts', function(e) {
		var self = $(this);
		var hostsList = $('#hostsList');
		var activeHosts = hostsList.find('.active');
		if (!activeHosts.length) {
			return;
		}

		var content = hostsEditor.getValue();

		if (activeHosts.hasClass('public-hosts')) {
			hostsData.publicHosts = content;
			$.post('/cgi-bin/hosts/save-public', {name: name, content: content});
		} else {
			var name = activeHosts.text();
			hostsData.hostsData[name] = content;
			$.post('/cgi-bin/hosts/save', {name: name, content: content});
			var glyphicon = newHostsList.find('.glyphicon-ok').remove();
			activeHosts.append(glyphicon.length ? glyphicon : glyphiconOk);
		}

		$('#hostsList').find('a.active').removeClass('changed');
		if (self.hasClass('confirm-hosts')) {
			$('.rules-dialog').modal('hide');
		}
	}).on('mouseenter', '.cm-js-type', function(e) {
		var self = $(this);
		if ((e.ctrlKey || e.metaKey) && getKey(self.text())) {
			self.addClass('has-key');
		}
	}).on('mouseenter', '.cm-js-weinre', function(e) {
		(e.ctrlKey || e.metaKey) && $(this).addClass('has-key');
	}).on('mouseleave', '.cm-js-type', function() {
		$(this).removeClass('has-key');
	}).on('click', '.cm-js-type', function(e) {
		var key, item;
		if (!e.ctrlKey && !e.metaKey) {
			return;
		}

		var self = $(this);
		var url = self.text();
		key = getKey(url);
		if (self.hasClass('cm-js-weinre')) {
			var weinreId;
			if (key) {
				weinreId = values[key];
			} else {
				weinreId = getKey(url, '<', '>') || getKey(url, '(', ')') || removeProtocol(url);
				if (!weinreId) {
					weinreId = url.substring(url.indexOf('://') + 3);
				}
			}

			if (weinreId) {
				openWeinre(weinreId);
				return;
			}
		}

		if (!key) {
			return;
		}

		$('.view-values').trigger('click');
		var valuesCon = $('#valuesList');
		var valuesList = valuesCon.find('a');
		for (var i = 0; i < valuesList.length; i++) {
			item = $(valuesList[i]);
			if (item.text() == key) {
				setTimeout(function() {
					item.trigger('click');
				}, 800);
				return;
			}
		}
		item = $('')
			.text(key).appendTo(valuesCon);
		setTimeout(function() {
			item.trigger('click');
			$('.apply-values').trigger('click');
		}, 800);

	});

	function removeProtocol(url) {
		var index = url.indexOf('://') + 3;
		return index != -1 ? url.substring(index) : url;
	}

	function getKey(url, start, end) {
		if (!url || !(url = $.trim(url))) {
			return null;
		}

		url = removeProtocol(url);
		if (url.indexOf(start || '{') == 0) {
			var index = url.lastIndexOf(end || '}');
			return index > 1 && url.substring(1, index);
		}

		return null;
	}

	$('#openWeinreBtn').click(function() {
		var weinreId = $.trim($('#weinreId').val());
		openWeinre(weinreId);
		$('#openWeinreDialog').modal('hide');
	});

	$('#weinreId').keyup(function(e) {
		e.keyCode == 13 && $('#openWeinreBtn').trigger('click');
	});

	function openWeinre(weinreId) {
		weinreId = (weinreId || 'weinre').substring(0, 120);
		window.open('http://weinre.local.whistlejs.com/client/#' + weinreId, weinreId);
	}

	var createHostsBtn = $('#createHostsBtn').click(function() {
		if (createHostsBtn.hasClass('disabled')) {
			return;
		}
		$('#createHostsDialog').modal();
		setTimeout(function() {
			try {$('#newHostsName').focus();} catch(e) {}
		}, 300);
	});

	var createHostsNameBtn = $('#createHostsNameBtn').click(function() {
		var name = $.trim($('#newHostsName').val());
		if (!name) {
			return;
		}

		for (var i in hostsData.hostsData) {
			if (i == name) {
				alert('该名称已存在。');
				return;
			}
		}
		createHosts(name).trigger('click');
		$.post('/cgi-bin/hosts/create', {name: name});
		$('#createHostsDialog').modal('toggle');
		updateCreateHostsBtnState();
		$('#newHostsName').val('');
		newHostsList.scrollTop(1000);
	});

	$('#newHostsName').keyup(function(e) {
		if (e.keyCode == 13) {
			createHostsNameBtn.trigger('click');
		}
	});

	function createHosts(name) {
		return $('').text(name).appendTo(newHostsList);
	}

	function updateCreateHostsBtnState() {
		if (newHostsList.find('.list-group-item').length >= 36) {
			createHostsBtn.addClass('disabled');
		} else {
			createHostsBtn.removeClass('disabled');
		}
	}

	function initRulesDialog() {
		if (inited) {
			return;
		}

		inited = true;

		if (hostsData == false) {
			loadData();
			return;
		};

		if (!hostsData) {
			return;
		}

		initActionBar(hostsData);
		var hostsList = hostsData.hostsList;
		var curHostsName = hostsData.curHostsName;
		var hasActive;
		for (var i = 0, len = hostsList.length; i < len; i++) {
			var name = hostsList[i];
			var item = createHosts(name);
			if (curHostsName == name) {
				item.append(glyphiconOk).trigger('click');
				hasActive = true;
				hostsEditor.setValue(hostsData.hostsData[name] || '');
				curHostsName = null;
			}
		}
		if (hostsData.disabled) {
			$('#publicHosts').find('.glyphicon-ok').hide();
			$('#enablePublicHosts').prop('checked', false);
		}
		updateCreateHostsBtnState();

		if (!hasActive) {
			$('#publicHosts').trigger('click');
		}

		updatePublicHostsState();
		setInterval(function() {
			var activeItem = $('#hostsList').find('a.active');
			var value = hostsEditor.getValue();
			var hosts = hostsData.hostsData[activeItem.text()];
			if (activeItem.hasClass('public-hosts')) {
				if((!value && !hostsData.publicHosts) || hostsData.publicHosts == value) {
					activeItem.removeClass('changed');
					return;
				}
			} else if((!value && !hosts) || hosts == value) {
					activeItem.removeClass('changed');
					return;
			}

			activeItem.addClass('changed');
		}, 360);
	}

	function addResizeEvents() {
		var editor = $('#hostsEditor')[0];
		var timeoutId;

		function resize() {
			clearTimeout(timeoutId);
			timeoutId = setTimeout(function() {
				hostsEditor.setSize(editor.offsetWidth, editor.offsetHeight + 1);
			}, 60);
		}

		$(window).on('resize', resize);
		resize();
	}

	module.exports = function init(data, valuesData, homePage) {
		hostsData = data || {};
		values = valuesData || {};
		$('#aboutVersion').text(hostsData.version);
		var aboutUrl = $('#aboutUrl');
		aboutUrl.attr('href', aboutUrl.attr('href').replace('{version}', hostsData.version));

		homePage ? initRulesDialog() : $('.rules-dialog').on('shown.bs.modal', initRulesDialog);
		$('#openWeinreDialog').on('shown.bs.modal', function() {
			setTimeout(function() {
				$('#weinreId').focus();
			}, 300);
		});

		var rulesSettingsList = $('#rulesSettingsList');
		$(document.body).on('click', function(e) {
			var target = $(e.target);
			if (!target.closest('#rulesSettings').length && !target.closest('#rulesSettingsList').length) {
				rulesSettingsList.hide();
			}
		});

		$('#rulesSettings').click(function() {
			rulesSettingsList.show();
		});

	};

	module.exports.resize = addResizeEvents;
});<commit_msg>weinre<commit_after>define('/style/js/biz/rules.js', function(require, exports, module) {
	var hostsData, inited, values;
	var newHostsList = $('#newHostsList');
	var glyphiconOk = '';

	var hostsEditor = CodeMirror($('#hostsEditor')[0], {
    	mode: 'text/whistle'
  	});

	var themeOptions = $('#themeOptions').change(function() {
		var theme = this.value;
		$.post('/cgi-bin/hosts/set-theme',{theme: theme});
		hostsEditor.setOption('theme', theme);
	});

	var fontSizeOptions = $('#fontSizeOptions').change(function() {
        var fontSize = this.value;
        $.post('/cgi-bin/hosts/set-font-size',{fontSize: fontSize});
        hostsEditor.getWrapperElement().style.fontSize = fontSize;
        hostsEditor.refresh();
	});

	var showLineNumbers = $('#showLineNumbers').change(function() {
		$.post('/cgi-bin/hosts/show-line-numbers',{showLineNumbers: this.checked ? 1 : 0});
		hostsEditor.setOption('lineNumbers', this.checked);
	});

	function initActionBar(data) {
		themeOptions.val(data.theme || 'cobalt').trigger('change');
		fontSizeOptions.val(data.fontSize || '16px').trigger('change');
		showLineNumbers.prop('checked', data.showLineNumbers == true);
		showLineNumbers.trigger('change');
	}

	var body = $(document.body).on('click', '.hosts-list .list-group-item', function() {
		var self = $(this);
		if (self.hasClass('create-hosts')) {
			return;
		}

		var hostsList = self.closest('.hosts-list');
		var activeItem = hostsList.find('.list-group-item.active').removeClass('active');
		var hostsName = activeItem.text();

		if (activeItem.hasClass('public-hosts')) {
			hostsData.publicHosts = hostsEditor.getValue();
		} else {
			hostsData.hostsData[hostsName] = hostsEditor.getValue();
		}

		self.addClass('active');

		var hostsNav = $('#hostsNav');
		hostsName = self.text();

		hostsNav.find('.hosts-title').text(hostsName);

		if (self.hasClass('public-hosts')) {
			hostsNav.find('.remove-hosts').hide();
			hostsNav.find('.enable-public-hosts').show();
			hostsEditor.setValue(hostsData.publicHosts || '');
		} else {
			hostsNav.find('.remove-hosts').show();
			hostsNav.find('.enable-public-hosts').hide();
			hostsEditor.setValue(hostsData.hostsData[hostsName] || '');
		}
	}).on('dblclick', '.hosts-list .list-group-item', function() {
		$('.apply-hosts').trigger('click');
	});

	body.on('click', '.enable-public-hosts', function() {
		var enable = $('#enablePublicHosts').prop('checked');
		var glyphicon = $('#publicHosts').find('.glyphicon-ok');
		enable ? glyphicon.show() : glyphicon.hide();
		updatePublicHostsState();
		$.post('/cgi-bin/hosts/enable',{enable: enable ? 1 : 0});
	});

	function updatePublicHostsState() {
		var enable = $('#enablePublicHosts').prop('checked');
		$('#publicHosts').css('color', enable ? '' : '#ccc')
		.attr('title', enable ? '先到自定义规则查找，如果没有匹配的再查找Public' : '公用环境已禁用');
	}

	body.on('click', '.remove-hosts', function() {
		if (confirm("确认删除？"))  {
			var hosts = newHostsList.find('.active');
			var name = hosts.text();

			$.post('/cgi-bin/hosts/remove',{name: name});
			var next = hosts.next();
			if (!next.length) {
				next = hosts.prev();
			}
			(next.length ? next : $('#publicHosts')).trigger('click');
			hosts.remove();
			delete hostsData.hostsData[name];
			updateCreateHostsBtnState();
		}

	});

	$('#hostsEditor').keyup(function(e) {
		if ((e.ctrlKey || e.metaKey)
				&& (e.keyCode == 13 || e.keyCode == 83)) {
			$('.apply-hosts').trigger('click');
		}
	}).keydown(function(e) {
		if (e.ctrlKey && e.keyCode == 83) {
			e.preventDefault();
			return false;
		}
	});

	body.on('click', '.apply-hosts,.confirm-hosts', function(e) {
		var self = $(this);
		var hostsList = $('#hostsList');
		var activeHosts = hostsList.find('.active');
		if (!activeHosts.length) {
			return;
		}

		var content = hostsEditor.getValue();

		if (activeHosts.hasClass('public-hosts')) {
			hostsData.publicHosts = content;
			$.post('/cgi-bin/hosts/save-public', {name: name, content: content});
		} else {
			var name = activeHosts.text();
			hostsData.hostsData[name] = content;
			$.post('/cgi-bin/hosts/save', {name: name, content: content});
			var glyphicon = newHostsList.find('.glyphicon-ok').remove();
			activeHosts.append(glyphicon.length ? glyphicon : glyphiconOk);
		}

		$('#hostsList').find('a.active').removeClass('changed');
		if (self.hasClass('confirm-hosts')) {
			$('.rules-dialog').modal('hide');
		}
	}).on('mouseenter', '.cm-js-type', function(e) {
		var self = $(this);
		if ((e.ctrlKey || e.metaKey) && getKey(self.text())) {
			self.addClass('has-key');
		}
	}).on('mouseenter', '.cm-js-weinre', function(e) {
		(e.ctrlKey || e.metaKey) && $(this).addClass('has-key');
	}).on('mouseleave', '.cm-js-type', function() {
		$(this).removeClass('has-key');
	}).on('click', '.cm-js-type', function(e) {
		var key, item;
		if (!e.ctrlKey && !e.metaKey) {
			return;
		}

		var self = $(this);
		var url = self.text();
		key = getKey(url);
		if (self.hasClass('cm-js-weinre')) {
			var weinreId;
			if (key) {
				weinreId = values[key];
			} else {
				weinreId = getKey(url, '<', '>') || getKey(url, '(', ')') || removeProtocol(url);
				if (!weinreId) {
					weinreId = url.substring(url.indexOf('://') + 3);
				}
			}

			if (weinreId) {
				openWeinre(weinreId);
				return;
			}
		}

		if (!key) {
			return;
		}

		$('.view-values').trigger('click');
		var valuesCon = $('#valuesList');
		var valuesList = valuesCon.find('a');
		for (var i = 0; i < valuesList.length; i++) {
			item = $(valuesList[i]);
			if (item.text() == key) {
				setTimeout(function() {
					item.trigger('click');
				}, 800);
				return;
			}
		}
		item = $('')
			.text(key).appendTo(valuesCon);
		setTimeout(function() {
			item.trigger('click');
			$('.apply-values').trigger('click');
		}, 800);

	});

	function removeProtocol(url) {
		var index = url.indexOf('://') + 3;
		return index != -1 ? url.substring(index) : url;
	}

	function getKey(url, start, end) {
		if (!url || !(url = $.trim(url))) {
			return null;
		}

		url = removeProtocol(url);
		if (url.indexOf(start || '{') == 0) {
			var index = url.lastIndexOf(end || '}');
			return index > 1 && url.substring(1, index);
		}

		return null;
	}

	$('#openWeinreBtn').click(function() {
		var weinreId = $.trim($('#weinreId').val());
		openWeinre(weinreId);
		$('#openWeinreDialog').modal('hide');
	});

	$('#weinreId').keyup(function(e) {
		e.keyCode == 13 && $('#openWeinreBtn').trigger('click');
	});

	function openWeinre(weinreId) {
		weinreId = (weinreId || 'weinre').substring(0, 120);
		window.open('http://weinre.local.whistlejs.com/client/#' + weinreId, weinreId);
	}

	var createHostsBtn = $('#createHostsBtn').click(function() {
		if (createHostsBtn.hasClass('disabled')) {
			return;
		}
		$('#createHostsDialog').modal();
		setTimeout(function() {
			try {$('#newHostsName').focus();} catch(e) {}
		}, 300);
	});

	var createHostsNameBtn = $('#createHostsNameBtn').click(function() {
		var name = $.trim($('#newHostsName').val());
		if (!name) {
			return;
		}

		for (var i in hostsData.hostsData) {
			if (i == name) {
				alert('该名称已存在。');
				return;
			}
		}
		createHosts(name).trigger('click');
		$.post('/cgi-bin/hosts/create', {name: name});
		$('#createHostsDialog').modal('toggle');
		updateCreateHostsBtnState();
		$('#newHostsName').val('');
		newHostsList.scrollTop(1000);
	});

	$('#newHostsName').keyup(function(e) {
		if (e.keyCode == 13) {
			createHostsNameBtn.trigger('click');
		}
	});

	function createHosts(name) {
		return $('').text(name).appendTo(newHostsList);
	}

	function updateCreateHostsBtnState() {
		if (newHostsList.find('.list-group-item').length >= 36) {
			createHostsBtn.addClass('disabled');
		} else {
			createHostsBtn.removeClass('disabled');
		}
	}

	function initRulesDialog() {
		if (inited) {
			return;
		}

		inited = true;

		if (hostsData == false) {
			loadData();
			return;
		};

		if (!hostsData) {
			return;
		}

		initActionBar(hostsData);
		var hostsList = hostsData.hostsList;
		var curHostsName = hostsData.curHostsName;
		var hasActive;
		for (var i = 0, len = hostsList.length; i < len; i++) {
			var name = hostsList[i];
			var item = createHosts(name);
			if (curHostsName == name) {
				item.append(glyphiconOk).trigger('click');
				hasActive = true;
				hostsEditor.setValue(hostsData.hostsData[name] || '');
				curHostsName = null;
			}
		}
		if (hostsData.disabled) {
			$('#publicHosts').find('.glyphicon-ok').hide();
			$('#enablePublicHosts').prop('checked', false);
		}
		updateCreateHostsBtnState();

		if (!hasActive) {
			$('#publicHosts').trigger('click');
		}

		updatePublicHostsState();
		setInterval(function() {
			var activeItem = $('#hostsList').find('a.active');
			var value = hostsEditor.getValue();
			var hosts = hostsData.hostsData[activeItem.text()];
			if (activeItem.hasClass('public-hosts')) {
				if((!value && !hostsData.publicHosts) || hostsData.publicHosts == value) {
					activeItem.removeClass('changed');
					return;
				}
			} else if((!value && !hosts) || hosts == value) {
					activeItem.removeClass('changed');
					return;
			}

			activeItem.addClass('changed');
		}, 360);
	}

	function addResizeEvents() {
		var editor = $('#hostsEditor')[0];
		var timeoutId;

		function resize() {
			clearTimeout(timeoutId);
			timeoutId = setTimeout(function() {
				hostsEditor.setSize(editor.offsetWidth, editor.offsetHeight);
			}, 60);
		}

		$(window).on('resize', resize);
		resize();
	}

	module.exports = function init(data, valuesData, homePage) {
		hostsData = data || {};
		values = valuesData || {};
		$('#aboutVersion').text(hostsData.version);
		var aboutUrl = $('#aboutUrl');
		aboutUrl.attr('href', aboutUrl.attr('href').replace('{version}', hostsData.version));

		homePage ? initRulesDialog() : $('.rules-dialog').on('shown.bs.modal', initRulesDialog);
		$('#openWeinreDialog').on('shown.bs.modal', function() {
			setTimeout(function() {
				$('#weinreId').focus();
			}, 300);
		});

		var rulesSettingsList = $('#rulesSettingsList');
		$(document.body).on('click', function(e) {
			var target = $(e.target);
			if (!target.closest('#rulesSettings').length && !target.closest('#rulesSettingsList').length) {
				rulesSettingsList.hide();
			}
		});

		$('#rulesSettings').click(function() {
			rulesSettingsList.show();
		});

	};

	module.exports.resize = addResizeEvents;
});<|endoftext|>


<commit_before>angular
  .module('lnPatterns')
  .factory('lnOGravityFormParser', lnOGravityFormParser);

/**
 *  TODO:
 *    - Render all 'Advanced' fields in the WP GF Form setup
 *    - Render all 'Post' fields in the WP GF Form setup
 *    - Render all 'Pricing' fields in the WP GF Form setup
 *
 *    - Add in paged form support
 *      - Render progress indicator if specified
 *      - Move buttons into page footers and out of form footer
 *      - Detect page number and use either Next or Submit button if it's the final page
 *
 *    - Consider how to re-structure this to use a more intelligent method map for
 *      input type parsing
 */

/*@ngInject*/
function lnOGravityFormParser($log, isValidParameterFilter) {

  var formTemplate = '' +
      '
' +
      '
' +
      '
{{title}}
' +
      '{{description}}' +
      '
' +
      '
' +
      '{{body}}' +
      '
' +
      '
' +
      '{{submit}}' +
      '
' +
      '
'
    ;

  // Public API
  //

  return {
    parse: parse
  };

  function parse(data) {
    $log.debug('lnOGravityFormParser.parse() ->', data.response);

    if (angular.isUndefined(data.response)) {
      $log.error('lnOGravityFormParser.parse() -> Form data unavailable!');
      return;
    }

    return angular
      .copy(formTemplate)
      .replace(/{{title}}/gi, data.response.title)
      .replace(/{{description}}/gi, data.response.description)
      .replace(/{{body}}/gi, parseAllFields(data.response.fields))
      .replace(/{{submit}}/gi, parseSubmitButton(data.response.button.text));
  }

  // Internal
  //

  // Fields from the 'Standard' panel in the GF Form builder
  //

  function parseSectionBreak(data) {
    return '
{{label}}
'
      .replace(/{{label}}/gi, data.label);
  }

  function parseRequiredFlag() {
    return '*';
  }

  function parseLabel(isFor, text, required) {
    return '{{text}}{{required}}'
      .replace(/{{for}}/gi, isFor)
      .replace(/{{text}}/gi, text)
      .replace(/{{required}}/gi, required === true ? parseRequiredFlag() : '');
  }

  function parseTextarea(data) {
    return '<textarea name="{{name}}" id="{{id}}" placeholder="{{placeholder}}" value="{{value}}"></textarea>'
      .replace(/{{name}}/gi, data.name)
      .replace(/{{id}}/gi, data.id)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{placeholder}}/gi, data.placeholder)
      .replace(/{{required}}/gi, data.isRequired);
  }

  function parseInput(data) {
    var _hidden = data.type === 'hidden';

    return '<input type="{{type}}" name="{{name}}" id="{{id}}" value="{{value}}" {{required}} placeholder="{{placeholder}}" class="{{hidden}}">'
      .replace(/{{type}}/gi, data.type)
      .replace(/{{id}}/gi, data.id)
      .replace(/{{name}}/gi, data.name)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{placeholder}}/gi, data.placeholder)
      .replace(/{{required}}/gi, data.isRequired ? 'required' : '')
      .replace(/{{selected}}/gi, data.isSelected)
      .replace(/{{hidden}}/gi, _hidden ? 'ng-hide' : '');
  }

  function parseGroupInput(data) {
    return '<input type="{{type}}" id="{{id}}" name="{{name}}"  value="{{value}}" {{checked}}>'
      .replace(/{{type}}/gi, data.type)
      .replace(/{{id}}/gi, data.id)
      .replace(/{{name}}/gi, data.name)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{checked}}/gi, data.isSelected === true ? 'checked' : '');
  }

  function parseGroupInputList(data, startIndex, nameHasIndexSuffix) {
    var _list = '
';
    var _index = startIndex || 0;

    angular.forEach(data.choices, function (choice) {
      choice.type = data.type;
      choice.id = 'choice_' + data.formId + '_' + data.id + '_' + _index;
      choice.name = 'input_' + data.id;

      if (nameHasIndexSuffix === true) {
        choice.name += '.' + _index;
      }

      _list += '
'
        + parseGroupInput(choice)
        + parseLabel(choice.id, choice.text, false)
        + '
';

      _index += 1;
    });

    _list += '
';

    return _list;
  }

  function parseSelectOption(data) {
    return '<option value="{{value}}" {{selected}}>{{text}}</option>'
      .replace(/{{value}}/gi, data.value)
      .replace(/{{selected}}/gi, data.isSelected === true ? 'selected="selected"' : '')
      .replace(/{{text}}/gi, data.text);
  }

  function parseSelectList(data, isMultiple) {
    var _list = '<select {{multiple}} name="{{name}}" id="{{id}}">';
    var _isMultiple = isMultiple === true;

    angular.forEach(data.choices, function (choice) {
      _list += parseSelectOption(choice);
    });

    _list += '</select>';

    return _list
      .replace(/{{multiple}}/gi, _isMultiple ? 'multiple="multiple"' : '')
      .replace(/{{name}}/gi, data.name)
      .replace(/{{id}}/gi, data.id);
  }

  // Fields from the 'Advanced' panel in the GF Form builder
  //

  /*
   function parseName() {

   }

   function parseDate() {

   }

   function parseTime() {

   }

   function parsePhone() {

   }

   function parseAddress() {

   }

   function parseWebsite() {

   }
   */

  // NOTE: This is currently implemented as a standard input, but actually has it's own type.
  function parseEmail(data) {
    return parseInput(data);
  }

  /*
   function parseFileupload() {

   }

   function parseList() {

   }
   */

  // Fields from the 'Post' panel in the GF Form builder
  //

  // Submit / Next button
  //

  function parseSubmitButton(text) {
    return '<button type="submit" ng-disabled="!$ctrl.form.$valid" class="submit">{{text}}</button>'
      .replace(/{{text}}/gi, text || 'Submit');
  }

  // Conglomeate methods
  //

  function parseField(fieldHTML, labelHTML, isHidden, formId, originalId) {
    return '
{{label}}{{field}}
'
      .replace(/{{hidden}}/gi, isHidden ? ' ng-hide' : '')
      .replace(/{{id}}/gi, 'field_' + formId + '_' + originalId)
      .replace(/{{label}}/gi, labelHTML)
      .replace(/{{field}}/gi, fieldHTML);
  }

  /**
   * TODO: think about how to re-structure this to reduce complexity
   *       and increase clarity
   */
  function parseAllFields(fieldsData) {
    var _fields = '
';

    angular.forEach(fieldsData, function (field) {
      var _fieldHTML;
      var _labelHTML;
      var _hidden = false;
      var _hasLabel = true;

      field.originalId = angular.copy(field.id);

      switch (field.type) {

        // 'Standard' field types
        case 'text':
        case 'number':
        case 'hidden':
          _hidden = field.type === 'hidden';
          field.id = 'input_' + field.formId + '_' + field.id;
          field.name = isValidParameterFilter(field.name) ? field.name : 'input_' + field.originalId;
          field.value = isValidParameterFilter(field.value) ? field.value : '';
          _fieldHTML = parseInput(field);
          break;
        case 'textarea':
          field.id = 'input_' + field.id;
          field.name = isValidParameterFilter(field.name) ? field.name : 'input_' + field.originalId;
          field.value = isValidParameterFilter(field.value) ? field.value : '';
          _fieldHTML = parseTextarea(field);
          break;
        case 'radio':
          _fieldHTML = parseGroupInputList(field);
          break;
        case 'checkbox':
          _fieldHTML = parseGroupInputList(field, 1, true);
          break;
        case 'select':
          field.id = 'input_' + field.id;
          field.name = field.id;
          _fieldHTML = parseSelectList(field);
          break;
        case 'multiselect':
          field.id = 'input_' + field.id;
          field.name = field.id + '[]';
          _fieldHTML = parseSelectList(field, true);
          break;
        case 'html':
          _hasLabel = false;
          _fieldHTML = field.content || ''; // Just render the HTML as-is
          break;
        case 'section':
          _hasLabel = false;
          _fieldHTML = parseSectionBreak(field);
          break;

        /*
         case 'page':
         _fieldHTML = parsePage(field);
         */

        // TODO: 'Advanced' field types
        /*
         case 'name':
         _fieldHTML = parseName(field);
         break;
         case 'date':
         _fieldHTML = parseDate(field);
         break;
         case 'time':
         _fieldHTML = parseTime(field);
         break;
         case 'phone':
         _fieldHTML = parsePhone(field);
         break;
         case 'address':
         _fieldHTML = parseAddress(field);
         break;
         */

        case 'email':
          field.id = 'input_' + field.formId + '_' + field.id;
          field.name = isValidParameterFilter(field.name) ? field.name : 'input_' + + field.originalId;
          field.value = isValidParameterFilter(field.value) ? field.value : '';
          _fieldHTML = parseEmail(field);
          break;

        /*
         case 'website':
         _fieldHTML = parseWebsite(field);
         break;
         case 'fileupload':
         _fieldHTML = parseFileupload(field);
         break;
         case 'list':
         _fieldHTML = parseList(field);
         break;
         */

        // TODO: 'Post' field types
        /*
         case 'post_title':
         break;
         case 'post_content':
         break;
         case 'post_excerpt':
         break;
         case 'post_tags':
         break;
         case 'post_category':
         break;
         case 'post_image':
         break;
         case 'post_custom_field':
         break;
         */

        // TODO: 'Price' field types
        /*
         case 'product':
         break;
         case 'quantity':
         break;
         case 'option':
         break;
         case 'shipping':
         break;
         case 'total':
         break;
         */
        // If we hit this, it's probably worth just going home and crying...
        default:
          break;
      }

      if (angular.isDefined(_fieldHTML)) {
        console.log(field.id,  '/ isRequired: ', field.isRequired);
        _labelHTML = (!_hidden && _hasLabel) ? parseLabel(field.id, field.label, field.isRequired) : '';
        _fields += parseField(_fieldHTML, _labelHTML, _hidden, field.formId, field.originalId);
      }
    });

    _fields += '
';

    return _fields;
  }

  /*
   function parsePage() {

   }

   function parsePages() {

   }
   */
}
<commit_msg>re-factor form parser to reduce complexity and make updates easy<commit_after>angular
  .module('lnPatterns')
  .factory('lnOGravityFormParser', lnOGravityFormParser);

/**
 *  TODO:
 *    - Render all 'Advanced' fields in the WP GF Form setup
 *    - Render all 'Post' fields in the WP GF Form setup
 *    - Render all 'Pricing' fields in the WP GF Form setup
 *
 *    - Add in paged form support
 *      - Render progress indicator if specified
 *      - Render Submit / Next buttons in page footers and not form footer if paged
 *      - Detect page number and use either Next or Submit button if it's the final page
 */

/*@ngInject*/
function lnOGravityFormParser($log, isValidParameterFilter) {
  var formTemplate = '' +
    '
' +
    '
' +
    '
{{title}}
' +
    '{{description}}' +
    '
' +
    '
' +
    '{{body}}' +
    '
' +
    '
' +
    '{{submit}}' +
    '
' +
    '
';

  var methodMap = {
    'text': parseInput,
    'number': parseInput,
    'hidden': parseInput,
    'textarea': parseTextarea,
    'radio': parseGroupInputList,
    'checkbox': parseGroupInputList,
    'select': parseSelectList,
    'multiselect': parseSelectList,
    'html': parseHTML,
    'section': parseSectionBreak,
    'email': parseEmail //,
    // TODO: implement the following input types
    /*
     'page' : parsePage,
     'name' : parseName,
     'date' : parseDate,
     'time' : parseTime,
     'phone' : parsePhone,
     'address' : parseAddress,
     'website' : parseWebsite,
     'fileupload' : parseFileupload,
     'list' : parseList,
     'post_title' : parsePostTitle,
     'post_content' : parsePostContent,
     'post_excerpt' : parsePostExcerpt,
     'post_tags' : parsePostTags,
     'post_category' : parseCategory,
     'post_image' : parseImage,
     'post_custom_field' : parseCustomField,
     'product' : parseProduct,
     'quantity' : parseQuantity,
     'option' : parseOption,
     'shipping' : parseShipping,
     'total': parseTotal
     */
  };

  // Public API
  //

  return {
    parse: parse
  };

  function parse(data) {
    $log.debug('lnOGravityFormParser.parse() ->', data.response);

    if (angular.isUndefined(data.response)) {
      $log.error('lnOGravityFormParser.parse() -> Form data unavailable!');
      return;
    }

    return angular
      .copy(formTemplate)
      .replace(/{{title}}/gi, data.response.title)
      .replace(/{{description}}/gi, data.response.description)
      .replace(/{{body}}/gi, parseAllFields(data.response.fields))
      .replace(/{{submit}}/gi, parseSubmitButton(data.response.button.text));
  }

  // Internal
  //

  function parseAllFields(fieldsData) {
    var _fields = '
';

    angular.forEach(fieldsData, function (field) {
      var _fieldHTML;
      var _labelHTML;
      var _method = methodMap[field.type];

      field.hidden = false;
      field.hasLabel = true;

      if (angular.isDefined(_method)) {
        _fieldHTML = _method(field);
      } else {
        $log.debug('lnOGravityFormParser.parseAllFields() -> Unsupported field type: ', field.type);
      }

      if (angular.isDefined(_fieldHTML)) {

        if (!field.hidden && field.hasLabel) {
          _labelHTML = parseLabel(field.modifiedId, field.label, field.isRequired);
        } else {
          _labelHTML = '';
        }

        _fields += parseField(_fieldHTML, _labelHTML, field.hidden, field.formId, field.id);
      }
    });

    _fields += '
';

    return _fields;
  }

  function parseField(fieldHTML, labelHTML, isHidden, formId, fieldId) {
    return '
{{label}}{{field}}
'
      .replace(/{{hidden}}/gi, isHidden ? ' ng-hide' : '')
      .replace(/{{id}}/gi, 'field_' + formId + '_' + fieldId)
      .replace(/{{label}}/gi, labelHTML)
      .replace(/{{field}}/gi, fieldHTML);
  }

  // Utility
  //

  function parseLabel(isFor, text, required) {
    return '{{text}}{{required}}'
      .replace(/{{for}}/gi, isFor)
      .replace(/{{text}}/gi, text)
      .replace(/{{required}}/gi, required === true ? parseRequiredFlag() : '');
  }

  function parseRequiredFlag() {
    return '*';
  }

  // Submit / Next button
  //

  function parseSubmitButton(text) {
    return '<button type="submit" ng-disabled="!$ctrl.form.$valid" class="submit">{{text}}</button>'
      .replace(/{{text}}/gi, text || 'Submit');
  }

  // Standard
  //

  function parseInput(data) {
    data.hidden = data.type === 'hidden';

    data.modifiedId = 'input_' + data.formId + '_' + data.id;
    data.name = isValidParameterFilter(data.name) ? data.name : 'input_' + data.id;
    data.value = isValidParameterFilter(data.value) ? data.value : '';

    return '<input type="{{type}}" name="{{name}}" id="{{id}}" value="{{value}}" {{required}} placeholder="{{placeholder}}" class="{{hidden}}">'
      .replace(/{{type}}/gi, data.type)
      .replace(/{{id}}/gi, data.modifiedId)
      .replace(/{{name}}/gi, data.name)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{placeholder}}/gi, data.placeholder)
      .replace(/{{required}}/gi, data.isRequired ? 'required' : '')
      .replace(/{{selected}}/gi, data.isSelected)
      .replace(/{{hidden}}/gi, data.hidden ? 'ng-hide' : '');
  }

  function parseTextarea(data) {
    data.modifiedId = 'input_' + data.formId + '_' + data.id;
    data.name = isValidParameterFilter(data.name) ? data.name : 'input_' + data.id;
    data.value = isValidParameterFilter(data.value) ? data.value : '';

    return '<textarea name="{{name}}" id="{{id}}" placeholder="{{placeholder}}" value="{{value}}"></textarea>'
      .replace(/{{name}}/gi, data.name)
      .replace(/{{id}}/gi, data.modifiedId)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{placeholder}}/gi, data.placeholder)
      .replace(/{{required}}/gi, data.isRequired);
  }

  function parseGroupInputList(data) {
    data.modifiedId = 'input_' + data.formId + '_' + data.id;

    var _list = '
';
    var _index = (data.type === 'checkbox') ? 1 : 0;
    var _nameHasIndexSuffix = (data.type === 'checkbox');

    angular.forEach(data.choices, function (choice) {
      choice.type = data.type;
      choice.modifiedId = 'choice_' + data.formId + '_' + data.id + '_' + _index;
      choice.name = 'input_' + data.id;

      if (_nameHasIndexSuffix === true) {
        choice.name += '.' + _index;
      }

      _list += '
'
        + parseGroupInput(choice)
        + parseLabel(choice.modifiedId, choice.text, false)
        + '
';

      _index += 1;
    });

    _list += '
';

    return _list;
  }

  function parseGroupInput(data) {
    return '<input type="{{type}}" id="{{id}}" name="{{name}}"  value="{{value}}" {{checked}}>'
      .replace(/{{type}}/gi, data.type)
      .replace(/{{id}}/gi, data.modifiedId)
      .replace(/{{name}}/gi, data.name)
      .replace(/{{value}}/gi, data.value)
      .replace(/{{checked}}/gi, data.isSelected === true ? 'checked' : '');
  }

  function parseSelectList(data) {
    data.modifiedId = 'input_' + data.formId + '_' + data.id;
    data.name = 'input_' + data.id;
    data.isMultiple = data.type === 'multiselect';

    if (data.isMultiple) {
      data.name += '[]';
    }

    var _list = '<select {{multiple}} name="{{name}}" id="{{id}}">';

    angular.forEach(data.choices, function (choice) {
      _list += parseSelectOption(choice);
    });

    _list += '</select>';

    return _list
      .replace(/{{multiple}}/gi, data.isMultiple ? 'multiple="multiple"' : '')
      .replace(/{{name}}/gi, data.name)
      .replace(/{{id}}/gi, data.modifiedId);
  }

  function parseSelectOption(data) {
    return '<option value="{{value}}" {{selected}}>{{text}}</option>'
      .replace(/{{value}}/gi, data.value)
      .replace(/{{selected}}/gi, data.isSelected === true ? 'selected="selected"' : '')
      .replace(/{{text}}/gi, data.text);
  }

  function parseSectionBreak(data) {
    data.hasLabel = false;
    return '
{{label}}
'
      .replace(/{{label}}/gi, data.label);
  }

  function parseHTML(data) {
    data.hasLabel = false;
    return data.content;
  }

  // Advanced

  // NOTE: This is currently implemented as a standard input, but actually has it's own type in the GF Admin,
  // So may need to add in extra logic here.
  function parseEmail(data) {
    return parseInput(data);
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

// small benchmark to execute with nodejs

var http = require('http')
var url = require('url');
var fs = require('fs');
var me = process.argv[1];

function usage(exit_code) {
  console.log("Usage: " + me + " [OPTIONS] <example_tile_url>");
  console.log("Options:");
  console.log(" -v                      verbose operations (off)");
  console.log(" --help                  print this help");
  console.log(" --key <string>          map authentication key (none)");
  console.log(" -n, --requests <num>    number of requests to send (1000)");
  console.log(" -C, --cached <num>      number of requests sharing same cache id (20)");
  console.log(" -c, --concurrent <num>  number of concurrent requests (20)");
  console.log(" --vp-size <num>x<num>   tiles per col, line in viewport (5x4)");
  console.log(" --zoom-levels <num>     number of zoom levels to span");
  process.exit(exit_code);
}

process.argv.shift(); // this will be "node" (argv[0])
process.argv.shift(); // this will be the script name  (argv[1])

var verbose = 0;
var urltemplate;
var map_key;
var cached_requests = 20;
var N = cached_requests*50; // number of requests (50 full viewports)
var concurrency = cached_requests; // number of concurrent requests
var cols = 5;
var lines = 4;
var zlevs = 2;

var arg;
while ( arg = process.argv.shift() ) {
  if ( arg == '-v' ) {
    ++verbose;
  }
  else if ( arg == '--key' ) {
    map_key=process.argv.shift();
  }
  else if ( arg == '--cached' || arg == '-C' ) {
    cached_requests=process.argv.shift();
  }
  else if ( arg == '--requests' || arg == '-n' ) {
    N = parseInt(process.argv.shift());
  }
  else if ( arg == '--vp-size' ) {
    arg = process.argv.shift();
    var parsed = arg.match(/([0-9]*)x([0-9]*)/);
    cols = parseInt(parsed[1]);
    lines = parseInt(parsed[2]);
  }
  else if ( arg == '--zoom-levels' ) {
    zlevs = parseInt(process.argv.shift());
  }
  else if ( arg == '--help' ) {
    usage(0);
  }
  else if ( arg == '-c' || arg == '--concurrent' ) {
    concurrency = parseInt(process.argv.shift());
  }
  else if ( ! urltemplate ) {
    urltemplate = arg;
  }
  else {
    usage(1);
  }
}

if ( ! urltemplate ) {
  usage(1);
}

var urlparsed = url.parse(urltemplate, true);
urlparsed.query = urlparsed.query || {};
delete urlparsed.search; // or url.format will not use urlparsed.query
var pathname_match = urlparsed.pathname.match(RegExp('(.*)/[0-9]+/[0-9]+/[0-9]+.png$', "i"));
if ( ! pathname_match ) {
  // For backward compatibility, add ZXY portion to url, if not found
  urlparsed.pathname += '/{z}/{x}/{y}.png';
} else {
  // Otherwise take the whole thing as a sample and convert ZXY
  // with the templated version
  //urlparsed.pathname += '/{z}/{x}/{y}.png';
  urlparsed.pathname = pathname_match[1];
  urlparsed.pathname += '/{z}/{x}/{y}.png';
}

if ( map_key ) {
  urlparsed.query['map_key'] = map_key;
}

urltemplate = url.format(urlparsed);

var start_time = Date.now();
function end() {
    var end_time = Date.now();
    var t = (end_time - start_time)/1000;
    console.log("");
    console.log("Server Host:          ", urlparsed.host);
    console.log("Template URL (path):  ", urlparsed.pathname);
    console.log("");
    console.log("Viewport size:        " + cols + "x" + lines);
    console.log("Zoom levels:          " + zlevs);
    console.log("");
    console.log("Requests per cache:   ", cached_requests);
    console.log("Complete requests:    ", ok);
    console.log("X-Cache hits:         ", xchits, " (" + Math.round((xchits/ok)*100) + "% of complete requests)" );
    console.log("X-Varnish hits:       ", xvhits, " (" + Math.round((xvhits/ok)*100) + "% of complete requests)" );
    console.log("");
    console.log("Failed requests:      ", error);
    console.log("Concurrency Level:    ", concurrency);
    console.log("Time taken for tests: ", t, " seconds");
    console.log("Requests per second:  ", (Math.round(((ok+error)/t)*100)/100), '[#/sec] (mean)');
    console.log("");
    process.exit(0);
}

var ok = 0;
var xchits = 0; // X-Cache hits
var xvhits = 0; // X-Varnish hits
var error = 0;

function check_end() {
  if ( error + ok === N ) end();
}

function fail(msg) {
  console.log(msg);
  ++ error;
  check_end();
}

function pass() {
  ++ ok;
  check_end();
}

http.globalAgent.maxSockets = concurrency;
var now = Date.now();
var cbprefix = 'wb_' + process.env.USER + '_' + process.pid + "_";
for(var i = 0; i < N; ++i) {

    // we start at zoom level 3 (TODO: make configurable)
    var z = 3 + Math.floor( (i/(cols*lines))%zlevs );
    var x = i%cols;
    var y = Math.floor(i/cols)%lines;

    // update cache_buster every "cached_requests" requests
    now += Math.floor(i/cached_requests);
    var cb = cbprefix + now;

    var nurlobj = url.parse(urltemplate, true);
    delete nurlobj.search; // or url.format will not use urlparsed.query
    nurlobj.pathname = nurlobj.pathname.replace('{z}', z).replace('{x}', x).replace('{y}', y);
    nurlobj.query = nurlobj.query || {};
    nurlobj.query['cache_buster'] = cb;

    var nurl = url.format(nurlobj);

    if ( verbose ) console.log("|+++|---> " + nurl);

    //console.log(opt.path)
    http.get(nurl, function(res) {
      res.body = '';
      if ( res.statusCode != 200 ) {
        res.on('data', function(chunk) {
          // Save only first chunk, to reduce cost of the operation
          if ( res.body.length == 0 ) res.body += chunk;
        });
      }
      res.on('end', function() {
        if ( res.statusCode == 200 ) {
          var xcache = res.headers['x-cache'];
          var xvarnish = res.headers['x-varnish'];
          if ( xcache && xcache.match(/hit/i) ) ++xchits;
          else {
            if ( xvarnish && xvarnish.match(/ /) ) ++xvhits;
          }
          if ( verbose ) {
            console.log("X-Cache: " + xcache);
            console.log("X-Varnish: " + xvarnish);
          }
          pass();
        }
        else {
          fail(res.statusCode + ' ' + nurl + ' ' + res.body);
          process.exit(1);
        }
      });
    }).on('error', function(e) {
        fail('unknown (http) error');
    });
}

var timeout = N * 1000;
setTimeout(function() {
  console.log("Not finished after " + (timeout/1000) + " seconds, giving up");
  process.exit(1);
}, timeout);
<commit_msg>Add "Hits summary" report<commit_after>#!/usr/bin/env node

// small benchmark to execute with nodejs

var http = require('http')
var url = require('url');
var fs = require('fs');
var me = process.argv[1];

function usage(exit_code) {
  console.log("Usage: " + me + " [OPTIONS] <example_tile_url>");
  console.log("Options:");
  console.log(" -v                      verbose operations (off)");
  console.log(" --help                  print this help");
  console.log(" --key <string>          map authentication key (none)");
  console.log(" -n, --requests <num>    number of requests to send (1000)");
  console.log(" -C, --cached <num>      number of requests sharing same cache id (20)");
  console.log(" -c, --concurrent <num>  number of concurrent requests (20)");
  console.log(" --vp-size <num>x<num>   tiles per col, line in viewport (5x4)");
  console.log(" --zoom-levels <num>     number of zoom levels to span");
  process.exit(exit_code);
}

process.argv.shift(); // this will be "node" (argv[0])
process.argv.shift(); // this will be the script name  (argv[1])

var verbose = 0;
var urltemplate;
var map_key;
var cached_requests = 20;
var N = cached_requests*50; // number of requests (50 full viewports)
var concurrency = cached_requests; // number of concurrent requests
var cols = 5;
var lines = 4;
var zlevs = 2;

var arg;
while ( arg = process.argv.shift() ) {
  if ( arg == '-v' ) {
    ++verbose;
  }
  else if ( arg == '--key' ) {
    map_key=process.argv.shift();
  }
  else if ( arg == '--cached' || arg == '-C' ) {
    cached_requests=process.argv.shift();
  }
  else if ( arg == '--requests' || arg == '-n' ) {
    N = parseInt(process.argv.shift());
  }
  else if ( arg == '--vp-size' ) {
    arg = process.argv.shift();
    var parsed = arg.match(/([0-9]*)x([0-9]*)/);
    cols = parseInt(parsed[1]);
    lines = parseInt(parsed[2]);
  }
  else if ( arg == '--zoom-levels' ) {
    zlevs = parseInt(process.argv.shift());
  }
  else if ( arg == '--help' ) {
    usage(0);
  }
  else if ( arg == '-c' || arg == '--concurrent' ) {
    concurrency = parseInt(process.argv.shift());
  }
  else if ( ! urltemplate ) {
    urltemplate = arg;
  }
  else {
    usage(1);
  }
}

if ( ! urltemplate ) {
  usage(1);
}

var urlparsed = url.parse(urltemplate, true);
urlparsed.query = urlparsed.query || {};
delete urlparsed.search; // or url.format will not use urlparsed.query
var pathname_match = urlparsed.pathname.match(RegExp('(.*)/[0-9]+/[0-9]+/[0-9]+.png$', "i"));
if ( ! pathname_match ) {
  // For backward compatibility, add ZXY portion to url, if not found
  urlparsed.pathname += '/{z}/{x}/{y}.png';
} else {
  // Otherwise take the whole thing as a sample and convert ZXY
  // with the templated version
  //urlparsed.pathname += '/{z}/{x}/{y}.png';
  urlparsed.pathname = pathname_match[1];
  urlparsed.pathname += '/{z}/{x}/{y}.png';
}

if ( map_key ) {
  urlparsed.query['map_key'] = map_key;
}

urltemplate = url.format(urlparsed);

var start_time = Date.now();
function end() {
    var end_time = Date.now();
    var t = (end_time - start_time)/1000;
    console.log("");
    console.log("Server Host:          ", urlparsed.host);
    console.log("Template URL (path):  ", urlparsed.pathname);
    console.log("");
    console.log("Viewport size:        " + cols + "x" + lines);
    console.log("Zoom levels:          " + zlevs);
    console.log("");
    console.log("Requests per cache:   ", cached_requests);
    console.log("Complete requests:    ", ok);
    console.log("");
    console.log("X-Cache hits:         ", xchits, " (" + Math.round((xchits/ok)*100) + "% of complete requests)" );
    console.log("X-Varnish hits:       ", xvhits, " (" + Math.round((xvhits/ok)*100) + "% of complete requests)" );
    console.log("Application hits:     ", ok-xchits-xvhits);
    console.log("Hits summary:         ", xchits, "-", xvhits, "-", (ok-xchits-xvhits));
    console.log("");
    console.log("Failed requests:      ", error);
    console.log("Concurrency Level:    ", concurrency);
    console.log("Time taken for tests: ", t, " seconds");
    console.log("Requests per second:  ", (Math.round(((ok+error)/t)*100)/100), '[#/sec] (mean)');
    console.log("");
    process.exit(0);
}

var ok = 0;
var xchits = 0; // X-Cache hits
var xvhits = 0; // X-Varnish hits
var error = 0;

function check_end() {
  if ( error + ok === N ) end();
}

function fail(msg) {
  console.log(msg);
  ++ error;
  check_end();
}

function pass() {
  ++ ok;
  check_end();
}

http.globalAgent.maxSockets = concurrency;
var now = Date.now();
var cbprefix = 'wb_' + process.env.USER + '_' + process.pid + "_";
for(var i = 0; i < N; ++i) {

    // we start at zoom level 3 (TODO: make configurable)
    var z = 3 + Math.floor( (i/(cols*lines))%zlevs );
    var x = i%cols;
    var y = Math.floor(i/cols)%lines;

    // update cache_buster every "cached_requests" requests
    now += Math.floor(i/cached_requests);
    var cb = cbprefix + now;

    var nurlobj = url.parse(urltemplate, true);
    delete nurlobj.search; // or url.format will not use urlparsed.query
    nurlobj.pathname = nurlobj.pathname.replace('{z}', z).replace('{x}', x).replace('{y}', y);
    nurlobj.query = nurlobj.query || {};
    nurlobj.query['cache_buster'] = cb;

    var nurl = url.format(nurlobj);

    if ( verbose ) console.log("|+++|---> " + nurl);

    //console.log(opt.path)
    http.get(nurl, function(res) {
      res.body = '';
      if ( res.statusCode != 200 ) {
        res.on('data', function(chunk) {
          // Save only first chunk, to reduce cost of the operation
          if ( res.body.length == 0 ) res.body += chunk;
        });
      }
      res.on('end', function() {
        if ( res.statusCode == 200 ) {
          var xcache = res.headers['x-cache'];
          var xvarnish = res.headers['x-varnish'];
          if ( xcache && xcache.match(/hit/i) ) ++xchits;
          else {
            if ( xvarnish && xvarnish.match(/ /) ) ++xvhits;
          }
          if ( verbose ) {
            console.log("X-Cache: " + xcache);
            console.log("X-Varnish: " + xvarnish);
          }
          pass();
        }
        else {
          fail(res.statusCode + ' ' + nurl + ' ' + res.body);
          process.exit(1);
        }
      });
    }).on('error', function(e) {
        fail('unknown (http) error');
    });
}

var timeout = N * 1000;
setTimeout(function() {
  console.log("Not finished after " + (timeout/1000) + " seconds, giving up");
  process.exit(1);
}, timeout);
<|endoftext|>


<commit_before>const path = require('path');
const fileUrl = require('file-url');
const failFast = require('protractor-fail-fast');

const failFastActive = (process.argv.length > 4 && process.argv[4] == '--params=ff');

exports.config = {

    seleniumAddress: 'http://localhost:9515/wd/hub',
    baseUrl: fileUrl(path.resolve(__dirname, '../../..') + '/dist/index.html'),

    specs: [
        'dist/test/e2e/matrix/*.spec.js',
        'dist/test/e2e/images/*.spec.js',
        'dist/test/e2e/resources/*.spec.js',
        'dist/test/e2e/map/*.spec.js',
        'dist/test/e2e/import/*.spec.js',
        'dist/test/e2e/settings/*.spec.js'
    ],

    allScriptsTimeout: 110000,
    getPageTimeout: 100000,
    framework: 'jasmine2',
    jasmineNodeOpts: {
        isVerbose: false,
        showColors: true,
        includeStackTrace: false,
        defaultTimeoutInterval: 400000
    },
    plugins: [{
        package: 'protractor-console-plugin',
        failOnWarning: true,
        failOnError: true,
        logWarnings: true,
        exclude: [
            "http://localhost:3001/" // pouchdb issues ignorable errors when syncing
        ]
    }],
    params: {
        appDataPath: 'test/test-temp',
        configPath: 'config/config.test.json',
        configTemplate: { 'dbs' : ['test'] }
    },
    onPrepare: function() {
        if (failFastActive) jasmine.getEnv().addReporter(failFast.init());

        var ProgressReporter = function() {

            this.specStarted = function(spec) {
                process.stdout.write("SPEC " + spec.fullName + " ")
            };

            this.specDone = function(spec) {

                console.log(spec.status.toUpperCase());

                browser.manage().logs().get('browser').then(function(browserLogs) {

                    var errLogs = browserLogs.filter(function (log) {
                        return (log.level.value_ > 900 && (log.message.
                            indexOf('Failed to load resource') === -1))});

                    if (errLogs.length > 0) {

                        console.log('--- There has been at least one browser console error (Spec '+spec.fullName+')!');

                        browserLogs.forEach(function(log){
                            if (log.level.value_ > 900) { // it's an error log
                                if (log.message.
                                    indexOf('Failed to load resource') === -1) {

                                    console.log("===> critical ERROR message: ",log.message);
                                } else {
                                    console.log("(uncritical) Error message: ",log.message);
                                }
                            } else {
                                console.log("Log message: ",log.message);
                            }
                        });
                    }

                });

            }
        };
        jasmine.getEnv().addReporter(new ProgressReporter());
    },
    afterLaunch: function() {
        if (failFastActive) failFast.clean();
    },
    /**
     * ng2 related configuration
     *
     * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
     * `rootEl`
     *
     */
    useAllAngular2AppRoots: true
};

if (failFastActive) exports.config.plugins.push(failFast.init());
<commit_msg>Fix config path in protractor-spectron.conf.js<commit_after>const path = require('path');
const fileUrl = require('file-url');
const failFast = require('protractor-fail-fast');

const failFastActive = (process.argv.length > 4 && process.argv[4] == '--params=ff');

exports.config = {

    seleniumAddress: 'http://localhost:9515/wd/hub',
    baseUrl: fileUrl(path.resolve(__dirname, '../../..') + '/dist/index.html'),

    specs: [
        'dist/test/e2e/matrix/*.spec.js',
        'dist/test/e2e/images/*.spec.js',
        'dist/test/e2e/resources/*.spec.js',
        'dist/test/e2e/map/*.spec.js',
        'dist/test/e2e/import/*.spec.js',
        'dist/test/e2e/settings/*.spec.js'
    ],

    allScriptsTimeout: 110000,
    getPageTimeout: 100000,
    framework: 'jasmine2',
    jasmineNodeOpts: {
        isVerbose: false,
        showColors: true,
        includeStackTrace: false,
        defaultTimeoutInterval: 400000
    },
    plugins: [{
        package: 'protractor-console-plugin',
        failOnWarning: true,
        failOnError: true,
        logWarnings: true,
        exclude: [
            "http://localhost:3001/" // pouchdb issues ignorable errors when syncing
        ]
    }],
    params: {
        appDataPath: 'test/test-temp',
        configPath: 'test/config/config.test.json',
        configTemplate: { 'dbs' : ['test'] }
    },
    onPrepare: function() {
        if (failFastActive) jasmine.getEnv().addReporter(failFast.init());

        var ProgressReporter = function() {

            this.specStarted = function(spec) {
                process.stdout.write("SPEC " + spec.fullName + " ")
            };

            this.specDone = function(spec) {

                console.log(spec.status.toUpperCase());

                browser.manage().logs().get('browser').then(function(browserLogs) {

                    var errLogs = browserLogs.filter(function (log) {
                        return (log.level.value_ > 900 && (log.message.
                            indexOf('Failed to load resource') === -1))});

                    if (errLogs.length > 0) {

                        console.log('--- There has been at least one browser console error (Spec '+spec.fullName+')!');

                        browserLogs.forEach(function(log){
                            if (log.level.value_ > 900) { // it's an error log
                                if (log.message.
                                    indexOf('Failed to load resource') === -1) {

                                    console.log("===> critical ERROR message: ",log.message);
                                } else {
                                    console.log("(uncritical) Error message: ",log.message);
                                }
                            } else {
                                console.log("Log message: ",log.message);
                            }
                        });
                    }

                });

            }
        };
        jasmine.getEnv().addReporter(new ProgressReporter());
    },
    afterLaunch: function() {
        if (failFastActive) failFast.clean();
    },
    /**
     * ng2 related configuration
     *
     * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
     * `rootEl`
     *
     */
    useAllAngular2AppRoots: true
};

if (failFastActive) exports.config.plugins.push(failFast.init());
<|endoftext|>


<commit_before>import { RouteRecognizer } from '../src/index';
import core from 'core-js';

const staticRoute = {'path': 'static','handler': {'name': 'static'}};
const dynamicRoute = {'path': 'dynamic/:id','handler': {'name': 'dynamic'}};

const routeTestData = [{
    title: 'empty path routes',
    route: {'path': '','handler': {'name': 'static'}},
    isDynamic: false,
    path: '/',
    params: {}
  }, {
    title: 'static routes',
    route: staticRoute,
    isDynamic: false,
    path: '/static',
    params: {}
  }, {
    title: 'dynamic routes',
    route: dynamicRoute,
    isDynamic: true,
    path: '/dynamic/test',
    params: { id: 'test' }
  }, {
    title: 'multi-segment dynamic routes',
    route: { 'path': 'dynamic/:id/:other','handler': { 'name': 'dynamic' }},
    isDynamic: true,
    path: '/dynamic/foo/bar',
    params: { id: 'foo', other: 'bar' }
  }, {
    title: 'duplicate dynamic routes',
    route: { 'path': 'dynamic/:id/:id','handler': { 'name': 'dynamic' }},
    isDynamic: true,
    path: '/dynamic/foo/foo',
    params: { id: 'foo' }
  }, {
    title: 'star routes',
    route: { 'path': 'star/*path','handler': { 'name': 'star' }},
    isDynamic: true,
    path: '/star/test/path',
    params: { path: 'test/path' }
  }, {
    title: 'dynamic star routes',
    route: { 'path': 'dynamic/:id/star/*path','handler': { 'name': 'star' }},
    isDynamic: true,
    path: '/dynamic/foo/star/test/path',
    params: { id: 'foo', path: 'test/path' }
  }];

describe('route recognizer', () => {
  it('should reject unknown routes', () => {
    let recognizer = new RouteRecognizer();

    expect(recognizer.hasRoute('static')).toBe(false);
    expect(() => recognizer.handlersFor('static')).toThrow();
    expect(() => recognizer.generate('static')).toThrow();
    expect(recognizer.recognize('/notfound')).toBeUndefined();
  });

  it('should register unnamed routes', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([{'path': 'b','handler': {}}]);

    expect(recognizer.names).toEqual({});
    expect(recognizer.recognize('/b')).toBeTruthy();
  });

  for (let routeTest of routeTestData) {
    it(`should recognize ${routeTest.title}`, () => {
      let recognizer = new RouteRecognizer();
      recognizer.add([routeTest.route]);

      let result = recognizer.recognize(routeTest.path);
      expect(result).toBeTruthy();
      expect(result.length).toBe(1);
      expect(result[0].handler).toEqual(routeTest.route.handler);
      expect(result[0].isDynamic).toBe(routeTest.isDynamic);
      expect(result[0].params).toEqual(routeTest.params);
    });

    it(`should generate ${routeTest.title}`, () => {
      let recognizer = new RouteRecognizer();
      recognizer.add([routeTest.route]);

      expect(recognizer.generate(routeTest.route.handler.name, routeTest.params))
        .toBe(routeTest.path);
    });
  }

  it('should require dynamic segment parameters when generating', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([dynamicRoute]);

    expect(() => recognizer.generate('dynamic')).toThrow();
    expect(() => recognizer.generate('dynamic', {})).toThrow();
    expect(() => recognizer.generate('dynamic', { id: null })).toThrow();
  });

  it('should generate URIs with extra parameters added to the query string', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([staticRoute]);
    recognizer.add([dynamicRoute]);

    expect(recognizer.generate('static')).toBe('/static');
    expect(recognizer.generate('static', {})).toBe('/static');
    expect(recognizer.generate('static', { id: 1 })).toBe('/static?id=1');

    expect(recognizer.generate('dynamic', { id: 1 })).toBe('/dynamic/1');
    expect(recognizer.generate('dynamic', { id: 1, test: 2 })).toBe('/dynamic/1?test=2');
  });

  it('should find handlers by route name', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([staticRoute]);

    expect(recognizer.hasRoute('static')).toBe(true);
    expect(recognizer.handlersFor('static')[0].handler).toEqual(staticRoute.handler);
  });

  it('should generate query strings', () => {
    let recognizer = new RouteRecognizer();
    let gen = recognizer.generateQueryString.bind(recognizer);

    expect(gen()).toBe('');
    expect(gen(null)).toBe('');
    expect(gen({})).toBe('');
    expect(gen({ a: null })).toBe('');

    expect(gen({ '': 'a' })).toBe('?=a');
    expect(gen({ a: 'b' })).toBe('?a=b');
    expect(gen({ a: 'b', c: 'd' })).toBe('?a=b&c=d');
    expect(gen({ a: 'b', c: null })).toBe('?a=b');

    expect(gen({ a: [ 'b', 'c' ]})).toBe('?a[]=b&a[]=c');
    expect(gen({ '&': [ 'b', 'c' ]})).toBe('?%26[]=b&%26[]=c');

    expect(gen({ a: '&' })).toBe('?a=%26');
    expect(gen({ '&': 'a' })).toBe('?%26=a');
    expect(gen({ a: true })).toBe('?a=true');
    expect(gen({ '$test': true })).toBe('?$test=true');
  });

  it('should parse query strings', () => {
    let recognizer = new RouteRecognizer();
    let parse = recognizer.parseQueryString.bind(recognizer);

    expect(parse('')).toEqual({});
    expect(parse('=')).toEqual({});
    expect(parse('&')).toEqual({});
    expect(parse('?')).toEqual({});

    expect(parse('a')).toEqual({ a: true });
    expect(parse('a&b')).toEqual({ a: true, b: true });
    expect(parse('a=')).toEqual({ a: '' });
    expect(parse('a=&b=')).toEqual({ a: '', b: '' });

    expect(parse('a=b')).toEqual({ a: 'b' });
    expect(parse('a=b&c=d')).toEqual({ a: 'b', c: 'd' });
    expect(parse('a=b&&c=d')).toEqual({ a: 'b', c: 'd' });
    expect(parse('a=b&a=c')).toEqual({ a: 'c' });

    expect(parse('a=%26')).toEqual({ a: '&' });
    expect(parse('%26=a')).toEqual({ '&': 'a' });
    expect(parse('%26[]=b&%26[]=c')).toEqual({ '&': [ 'b', 'c' ]});
  });
});
<commit_msg>fix(tests): correct import source<commit_after>import { RouteRecognizer } from '../src/route-recognizer';
import core from 'core-js';

const staticRoute = {'path': 'static','handler': {'name': 'static'}};
const dynamicRoute = {'path': 'dynamic/:id','handler': {'name': 'dynamic'}};

const routeTestData = [{
    title: 'empty path routes',
    route: {'path': '','handler': {'name': 'static'}},
    isDynamic: false,
    path: '/',
    params: {}
  }, {
    title: 'static routes',
    route: staticRoute,
    isDynamic: false,
    path: '/static',
    params: {}
  }, {
    title: 'dynamic routes',
    route: dynamicRoute,
    isDynamic: true,
    path: '/dynamic/test',
    params: { id: 'test' }
  }, {
    title: 'multi-segment dynamic routes',
    route: { 'path': 'dynamic/:id/:other','handler': { 'name': 'dynamic' }},
    isDynamic: true,
    path: '/dynamic/foo/bar',
    params: { id: 'foo', other: 'bar' }
  }, {
    title: 'duplicate dynamic routes',
    route: { 'path': 'dynamic/:id/:id','handler': { 'name': 'dynamic' }},
    isDynamic: true,
    path: '/dynamic/foo/foo',
    params: { id: 'foo' }
  }, {
    title: 'star routes',
    route: { 'path': 'star/*path','handler': { 'name': 'star' }},
    isDynamic: true,
    path: '/star/test/path',
    params: { path: 'test/path' }
  }, {
    title: 'dynamic star routes',
    route: { 'path': 'dynamic/:id/star/*path','handler': { 'name': 'star' }},
    isDynamic: true,
    path: '/dynamic/foo/star/test/path',
    params: { id: 'foo', path: 'test/path' }
  }];

describe('route recognizer', () => {
  it('should reject unknown routes', () => {
    let recognizer = new RouteRecognizer();

    expect(recognizer.hasRoute('static')).toBe(false);
    expect(() => recognizer.handlersFor('static')).toThrow();
    expect(() => recognizer.generate('static')).toThrow();
    expect(recognizer.recognize('/notfound')).toBeUndefined();
  });

  it('should register unnamed routes', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([{'path': 'b','handler': {}}]);

    expect(recognizer.names).toEqual({});
    expect(recognizer.recognize('/b')).toBeTruthy();
  });

  for (let routeTest of routeTestData) {
    it(`should recognize ${routeTest.title}`, () => {
      let recognizer = new RouteRecognizer();
      recognizer.add([routeTest.route]);

      let result = recognizer.recognize(routeTest.path);
      expect(result).toBeTruthy();
      expect(result.length).toBe(1);
      expect(result[0].handler).toEqual(routeTest.route.handler);
      expect(result[0].isDynamic).toBe(routeTest.isDynamic);
      expect(result[0].params).toEqual(routeTest.params);
    });

    it(`should generate ${routeTest.title}`, () => {
      let recognizer = new RouteRecognizer();
      recognizer.add([routeTest.route]);

      expect(recognizer.generate(routeTest.route.handler.name, routeTest.params))
        .toBe(routeTest.path);
    });
  }

  it('should require dynamic segment parameters when generating', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([dynamicRoute]);

    expect(() => recognizer.generate('dynamic')).toThrow();
    expect(() => recognizer.generate('dynamic', {})).toThrow();
    expect(() => recognizer.generate('dynamic', { id: null })).toThrow();
  });

  it('should generate URIs with extra parameters added to the query string', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([staticRoute]);
    recognizer.add([dynamicRoute]);

    expect(recognizer.generate('static')).toBe('/static');
    expect(recognizer.generate('static', {})).toBe('/static');
    expect(recognizer.generate('static', { id: 1 })).toBe('/static?id=1');

    expect(recognizer.generate('dynamic', { id: 1 })).toBe('/dynamic/1');
    expect(recognizer.generate('dynamic', { id: 1, test: 2 })).toBe('/dynamic/1?test=2');
  });

  it('should find handlers by route name', () => {
    let recognizer = new RouteRecognizer();
    recognizer.add([staticRoute]);

    expect(recognizer.hasRoute('static')).toBe(true);
    expect(recognizer.handlersFor('static')[0].handler).toEqual(staticRoute.handler);
  });

  it('should generate query strings', () => {
    let recognizer = new RouteRecognizer();
    let gen = recognizer.generateQueryString.bind(recognizer);

    expect(gen()).toBe('');
    expect(gen(null)).toBe('');
    expect(gen({})).toBe('');
    expect(gen({ a: null })).toBe('');

    expect(gen({ '': 'a' })).toBe('?=a');
    expect(gen({ a: 'b' })).toBe('?a=b');
    expect(gen({ a: 'b', c: 'd' })).toBe('?a=b&c=d');
    expect(gen({ a: 'b', c: null })).toBe('?a=b');

    expect(gen({ a: [ 'b', 'c' ]})).toBe('?a[]=b&a[]=c');
    expect(gen({ '&': [ 'b', 'c' ]})).toBe('?%26[]=b&%26[]=c');

    expect(gen({ a: '&' })).toBe('?a=%26');
    expect(gen({ '&': 'a' })).toBe('?%26=a');
    expect(gen({ a: true })).toBe('?a=true');
    expect(gen({ '$test': true })).toBe('?$test=true');
  });

  it('should parse query strings', () => {
    let recognizer = new RouteRecognizer();
    let parse = recognizer.parseQueryString.bind(recognizer);

    expect(parse('')).toEqual({});
    expect(parse('=')).toEqual({});
    expect(parse('&')).toEqual({});
    expect(parse('?')).toEqual({});

    expect(parse('a')).toEqual({ a: true });
    expect(parse('a&b')).toEqual({ a: true, b: true });
    expect(parse('a=')).toEqual({ a: '' });
    expect(parse('a=&b=')).toEqual({ a: '', b: '' });

    expect(parse('a=b')).toEqual({ a: 'b' });
    expect(parse('a=b&c=d')).toEqual({ a: 'b', c: 'd' });
    expect(parse('a=b&&c=d')).toEqual({ a: 'b', c: 'd' });
    expect(parse('a=b&a=c')).toEqual({ a: 'c' });

    expect(parse('a=%26')).toEqual({ a: '&' });
    expect(parse('%26=a')).toEqual({ '&': 'a' });
    expect(parse('%26[]=b&%26[]=c')).toEqual({ '&': [ 'b', 'c' ]});
  });
});
<|endoftext|>


<commit_before>describe('links helper tests', function () {
  'use strict';
  var links;

  beforeEach(function (done) {
    this.timeout(10000);

    require(['cs!helpers/links'], function () {
      links = arguments[0];
      done();
    });
  });

  describe('get path tests', function () {
    it('should return the root url', function () {
      // not content
      var page = 'nothing';
      var data = {
        model: {
          getVersionedId: function () {
            return 'not real';
          }
        }
      };
      links.getPath(page, data).should.equal('/');
    });
    it('should append fake uuid and page title to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return 'not real';
          },
          get: function (which) {
            switch (which) {
              case 'shortId':
                return 'shortId';
              case 'version':
                return 'version';
              case 'title':
                return 'title';
              default:
                return 'something';
            }
          },
          isBook: function () {
            return false;
          }
        }
      };
      links.getPath(page, data).should.equal('/contents/shortId@version/title');
    });
    it('should append uuid and page title from settings to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return '031da8d3-b525-429c-80cf-6c8ed997733a@8.1';
          },
          get: function () {
            return 'book title';
          },
          isBook: function () {
            return false;
          }
        }
      };
      links.getPath(page, data).should.equal('/contents/book title@book title/book-title');
    });
    it('should append uuid, book info and page title to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return '031da8d3-b525-429c-80cf-6c8ed997733a@8.1';
          },
          get: function () {
            return 'book name';
          },
          _lookupPage: function () {
            return {
              get: function () {
                return 'page title!';
              }
            };
          },
          isBook: function () {
            return true;
          }
        },
        page: 'page'
      };
      links.getPath(page, data).should.equal('/contents/book name@book name:page title!@page title!/page-title');
    });
  });
  describe('serialize query tests', function () {
    it('should serialize query string in to an object', function () {
      var query =
        'search?author=Smith&title=Physics&subject=%22Science%20and%20Technology%22&keyword=Velocity&type=page';
      var queryObj = links.serializeQuery(query);
      queryObj.author.should.equal('Smith');
      queryObj.title.should.equal('Physics');
      queryObj.subject.should.equal('"Science and Technology"');
      queryObj.keyword.should.equal('Velocity');
      queryObj.type.should.equal('page');
    });
    it('should serialize query with encoded &, ?, and = in fields', function () {
      var query = 'search?author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8';
      var queryObj = links.serializeQuery(query);
      queryObj.author.should.equal('"Dr. Gray?"');
      queryObj.title.should.equal('"Statics & Dynamics"');
      queryObj.keyword.should.equal('x=8');
    });
    // only finds the last one
    it('should serialize query with more than one keyword', function () {
      var query = 'search?keyword=Velocity&keyword=Statics';
      var queryObj = links.serializeQuery(query);
      queryObj.keyword.should.equal('Statics');
    });
  });
  describe('param tests', function () {
    it('should turn object in to query string', function () {
      var queryObj = {
        author: 'Smith',
        title: 'Physics',
        subject: '"Science and Technology"',
        keyword: 'Velocity',
        type: 'page'
      };
      links.param(queryObj).should.equal('author=Smith&title=Physics&subject=%22Science%20and%20' +
        'Technology%22&keyword=Velocity&type=page');
    });
    // doesn't encode correctly to be handled by the serialize function
    it('should encode &, =, and ?', function () {
      var queryObj = {
        author: 'Dr. Gray?',
        title: '"Statics & Dynamics"',
        keyword: 'x = 8'
      };
      links.param(queryObj);
      //.should.equal('author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8');
    });
  });

  it('should serialize and deserialize a query', function () {
    var query = 'author=Smith&title=Physics&subject=%22Science%20and%20Technology%22&keyword=Velocity&type=page';
    var queryObj = links.serializeQuery(query);
    links.param(queryObj).should.equal(query);
  });

  // Doesn't work either becuase encoding doesn't work for these characters
  it('should serialize and deserialize a query with &, ?, and =', function () {
    var query = 'author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8';
    var queryObj = links.serializeQuery(query);
    links.param(queryObj); //.should.equal(query);
  });
});
<commit_msg>Update shortUuid tests<commit_after>describe('links helper tests', function () {
  'use strict';
  var links;

  beforeEach(function (done) {
    this.timeout(10000);

    require(['cs!helpers/links'], function () {
      links = arguments[0];
      done();
    });
  });

  describe('get path tests', function () {
    it('should return the root url', function () {
      // not content
      var page = 'nothing';
      var data = {
        model: {
          getVersionedId: function () {
            return 'not real';
          }
        }
      };
      links.getPath(page, data).should.equal('/');
    });
    it('should append fake uuid and page title to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return 'not real';
          },
          getShortUuid: function () {
            return 'shortId';
          },
          get: function (which) {
            switch (which) {
              case 'shortId':
                return 'book title';
              case 'version':
                return 'version';
              case 'title':
                return 'title';
              default:
                return 'something';
            }
          },
          isBook: function () {
            return false;
          }
        }
      };
      links.getPath(page, data).should.equal('/contents/shortId@version/title');
    });
    it('should append uuid and page title from settings to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return '031da8d3-b525-429c-80cf-6c8ed997733a@8.1';
          },
          getShortUuid: function () {
            return 'book title';
          },
          get: function () {
            return 'book title';
          },
          isBook: function () {
            return false;
          }
        }
      };
      links.getPath(page, data).should.equal('/contents/book title@book title/book-title');
    });
    it('should append uuid, book info and page title to url', function () {
      var page = 'contents';
      var data = {
        model: {
          getVersionedId: function () {
            return '031da8d3-b525-429c-80cf-6c8ed997733a@8.1';
          },
          getShortUuid: function () {
            return 'book name';
          },
          get: function () {
            return 'book name';
          },
          _lookupPage: function () {
            return {
              get: function () {
                return 'page title!';
              },
              getShortUuid: function () {
                return 'page title!';
              },
            };
          },
          isBook: function () {
            return true;
          }
        },
        page: 'page'
      };
      links.getPath(page, data).should.equal('/contents/book name@book name:page title!@page title!/page-title');
    });
  });
  describe('serialize query tests', function () {
    it('should serialize query string in to an object', function () {
      var query =
        'search?author=Smith&title=Physics&subject=%22Science%20and%20Technology%22&keyword=Velocity&type=page';
      var queryObj = links.serializeQuery(query);
      queryObj.author.should.equal('Smith');
      queryObj.title.should.equal('Physics');
      queryObj.subject.should.equal('"Science and Technology"');
      queryObj.keyword.should.equal('Velocity');
      queryObj.type.should.equal('page');
    });
    it('should serialize query with encoded &, ?, and = in fields', function () {
      var query = 'search?author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8';
      var queryObj = links.serializeQuery(query);
      queryObj.author.should.equal('"Dr. Gray?"');
      queryObj.title.should.equal('"Statics & Dynamics"');
      queryObj.keyword.should.equal('x=8');
    });
    // only finds the last one
    it('should serialize query with more than one keyword', function () {
      var query = 'search?keyword=Velocity&keyword=Statics';
      var queryObj = links.serializeQuery(query);
      queryObj.keyword.should.equal('Statics');
    });
  });
  describe('param tests', function () {
    it('should turn object in to query string', function () {
      var queryObj = {
        author: 'Smith',
        title: 'Physics',
        subject: '"Science and Technology"',
        keyword: 'Velocity',
        type: 'page'
      };
      links.param(queryObj).should.equal('author=Smith&title=Physics&subject=%22Science%20and%20' +
        'Technology%22&keyword=Velocity&type=page');
    });
    // doesn't encode correctly to be handled by the serialize function
    it('should encode &, =, and ?', function () {
      var queryObj = {
        author: 'Dr. Gray?',
        title: '"Statics & Dynamics"',
        keyword: 'x = 8'
      };
      links.param(queryObj);
      //.should.equal('author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8');
    });
  });

  it('should serialize and deserialize a query', function () {
    var query = 'author=Smith&title=Physics&subject=%22Science%20and%20Technology%22&keyword=Velocity&type=page';
    var queryObj = links.serializeQuery(query);
    links.param(queryObj).should.equal(query);
  });

  // Doesn't work either becuase encoding doesn't work for these characters
  it('should serialize and deserialize a query with &, ?, and =', function () {
    var query = 'author="Dr.%20Gray%3F"&title=%22Statics%20%26%20Dynamics%22&keyword=x%3D8';
    var queryObj = links.serializeQuery(query);
    links.param(queryObj); //.should.equal(query);
  });
});
<|endoftext|>


<commit_before>define(function(require, exports, module) {

    // Load dependent modules
    var CommandManager      // loaded from brackets.test
    ,   Commands            // loaded from brackets.test
    ,   DocumentManager     // loaded from brackets.test
    ,    ProjectManager        // loaded from brackets.test
    ,   SpecRunnerUtils     = require("./SpecRunnerUtils.js");
    ;

    // FIXME (jasonsj): these tests are ommitted when launching in the main app window
    if (window.opener) {

        beforeEach(function() {
    //        this.app = window.open(SpecRunnerUtils.getBracketsSourceRoot() + "/index.html");
            // TODO: this will only work if run from the main Brackets window (not from jasmine.sh)
            this.app = window.opener;

            // Load module instances from brackets.test
            CommandManager      = this.app.brackets.test.CommandManager;
            Commands            = this.app.brackets.test.Commands;
            DocumentManager     = this.app.brackets.test.DocumentManager;
            ProjectManager      = this.app.brackets.test.ProjectManager;

            this.app.location.reload();
            this.testPath = SpecRunnerUtils.getTestPath("/spec/WorkingSetView-test-files/");
            var isReady = false;
            $(this.app.document).ready(function() {
                isReady = true;
            });
            waitsFor(function() { return isReady; }, 5000);

            var didOpen = false, gotError = false;

            // Open a directory
            ProjectManager.loadProject(this.testPath);

            var openAndMakeDirty = function (path){
                // open file
                runs(function() {
                    CommandManager.execute(Commands.FILE_OPEN, path)
                        .done(function() { didOpen = true; })
                        .fail(function() { gotError = true; });
                });
                waitsFor(function() { return didOpen && !gotError; }, "FILE_OPEN on file timeout", 1000);

                // change editor content to make doc dirty
                runs(function() {
                    var editor = DocumentManager.getCurrentDocument()._editor;
                    editor.setValue("dirty document");
                    expect(DocumentManager.getCurrentDocument().isDirty).toBe(true);
                });

            };

            openAndMakeDirty(this.testPath + "/file_one.js");
            openAndMakeDirty(this.testPath + "/file_two.js");

        });

    describe("WorkingSetView", function(){

        it("should add a list item when a file is dirtied", function() {
            // check if files are added to work set and dirty icons are present
            runs(function() {
                var listItems = this.app.$("#open-files-container > ul").children();
                expect( listItems.length ).toBe(2);
                expect( listItems.find("a").get(0).text == "file_one.js" ).toBeTruthy();
                expect( listItems.find(".file-status-icon").length).toBe(2);

            });

        });

        it("should remove a list item when a file is closed", function() {
            DocumentManager.getCurrentDocument().markClean(); // so we can close without a save dialog

            // close the document
            runs(function() {
                CommandManager.execute(Commands.FILE_CLOSE)
                    .done(function() { didClose = true; })
                    .fail(function() { gotError = true; });
            });

            // check there are no list items
            runs(function() {
                var listItems = this.app.$("#open-files-container > ul").children();
                expect( listItems.length ).toBe(1);
            });

        });

        // TODO Ty: Can't write this test yet until Jason's persistant work is complete
        // it("should rebuild the ui from the model correctly", function() {
        //
        // });

        it("should close a file when the user clicks the close button", function() {
            var $ = this.app.$;

            // make 2nd doc clean
            var docList = DocumentManager.getWorkingSet();
            docList[1].markClean();

            // make the first one active
            DocumentManager.showInEditor( docList[0]);

            // hover over and click on close icon of 2nd list item
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('mouseover');
            var closeIcon = secondItem.find(".file-status-icon");
            expect(closeIcon.length).toBe(1) ;

            // simulate click
            closeIcon.trigger('click');

            var listItems = $("#open-files-container > ul").children();
            expect( listItems.length ).toBe(1);
            expect( listItems.find("a").get(0).text == "file_one.js" ).toBeTruthy();

        });

        it("should remove dirty icon when file becomes clean", function() {
            // check that dirty icon is removed when docs are cleaned
            var docList = DocumentManager.getWorkingSet();
           docList[0].markClean();
           var listItems = this.app.$("#open-files-container > ul").children();
           expect( listItems.find(".file-status-icon dirty").length).toBe(0);

        });

       it("should make a file that is clicked the current one in the editor", function() {

       });

        });
    }
});<commit_msg>Working set unit test work<commit_after>define(function(require, exports, module) {

    // Load dependent modules
    var CommandManager      // loaded from brackets.test
    ,   Commands            // loaded from brackets.test
    ,   DocumentManager     // loaded from brackets.test
    ,    ProjectManager        // loaded from brackets.test
    ,   SpecRunnerUtils     = require("./SpecRunnerUtils.js");
    ;

    // FIXME (jasonsj): these tests are ommitted when launching in the main app window
    if (window.opener) {

        beforeEach(function() {
    //        this.app = window.open(SpecRunnerUtils.getBracketsSourceRoot() + "/index.html");
            // TODO: this will only work if run from the main Brackets window (not from jasmine.sh)
            this.app = window.opener;

            // Load module instances from brackets.test
            CommandManager      = this.app.brackets.test.CommandManager;
            Commands            = this.app.brackets.test.Commands;
            DocumentManager     = this.app.brackets.test.DocumentManager;
            ProjectManager      = this.app.brackets.test.ProjectManager;

            this.app.location.reload();
            this.testPath = SpecRunnerUtils.getTestPath("/spec/WorkingSetView-test-files/");
            var isReady = false;
            $(this.app.document).ready(function() {
                isReady = true;
            });
            waitsFor(function() { return isReady; }, 5000);

            var didOpen = false, gotError = false;

            // Open a directory
            ProjectManager.loadProject(this.testPath);

            var openAndMakeDirty = function (path){
                // open file
                runs(function() {
                    CommandManager.execute(Commands.FILE_OPEN, path)
                        .done(function() { didOpen = true; })
                        .fail(function() { gotError = true; });
                });
                waitsFor(function() { return didOpen && !gotError; }, "FILE_OPEN on file timeout", 1000);

                // change editor content to make doc dirty
                runs(function() {
                    var editor = DocumentManager.getCurrentDocument()._editor;
                    editor.setValue("dirty document");
                    expect(DocumentManager.getCurrentDocument().isDirty).toBe(true);
                });

            };

            openAndMakeDirty(this.testPath + "/file_one.js");
            openAndMakeDirty(this.testPath + "/file_two.js");

        });

    describe("WorkingSetView", function(){

        it("should add a list item when a file is dirtied", function() {
            // check if files are added to work set and dirty icons are present
            runs(function() {
                var listItems = this.app.$("#open-files-container > ul").children();
                expect( listItems.length ).toBe(2);
                expect( listItems.find("a").get(0).text == "file_one.js" ).toBeTruthy();
                expect( listItems.find(".file-status-icon").length).toBe(2);

            });

        });

        it("should remove a list item when a file is closed", function() {
            DocumentManager.getCurrentDocument().markClean(); // so we can close without a save dialog

            // close the document
            runs(function() {
                CommandManager.execute(Commands.FILE_CLOSE)
                    .done(function() { didClose = true; })
                    .fail(function() { gotError = true; });
            });

            // check there are no list items
            runs(function() {
                var listItems = this.app.$("#open-files-container > ul").children();
                expect( listItems.length ).toBe(1);
            });

        });

        it("should make a file that is clicked the current one in the editor", function() {
            var $ = this.app.$;
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('click');

            var listItems = $("#open-files-container > ul").children();
            expect( $(listItems[0]).hasClass("selected") ).not.toBeTruthy();
            expect( $(listItems[1]).hasClass("selected") ).toBeTruthy();

        });

        // TODO Ty: Can't write this test yet until Jason's persistant work is complete
        // it("should rebuild the ui from the model correctly", function() {
        //
        // });

        it("should close a file when the user clicks the close button", function() {
            var $ = this.app.$;

            // make 2nd doc clean
            var docList = DocumentManager.getWorkingSet();
            docList[1].markClean();

            // make the first one active
            DocumentManager.showInEditor(docList[0]);

            // hover over and click on close icon of 2nd list item
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('mouseover');
            var closeIcon = secondItem.find(".file-status-icon");
            expect(closeIcon.length).toBe(1) ;

            // simulate click
            closeIcon.trigger('click');

            var listItems = $("#open-files-container > ul").children();
            expect( listItems.length ).toBe(1);
            expect( listItems.find("a").get(0).text == "file_one.js" ).toBeTruthy();

        });

        it("should remove dirty icon when file becomes clean", function() {
            // check that dirty icon is removed when docs are cleaned
            var docList = DocumentManager.getWorkingSet();
           docList[0].markClean();
           var listItems = this.app.$("#open-files-container > ul").children();
           expect( listItems.find(".file-status-icon dirty").length).toBe(0);

        });

        });
    }
});<|endoftext|>