<commit_before>/**
 * Created by menzhongxin on 2016/10/26.
 */
var METHOD = ['get', 'post', 'put', 'delete']
  , util = require('./utils.js');

var BaseRouter = function(){};
module.exports = new BaseRouter();

/**
 * 迭代在路由头部插入中间件,按照中间件的顺序添加
 * @param args
 * @param middleware
 */
var insertMiddleware = function(args, middleware){
  "use strict";
  !util.isArray(middleware) && (middleware = [middleware]);
  for(var i = 0; i < middleware.length; i ++) {
    args.splice(i + 1, 0, middleware[i]);
  }
};

/**
 * 匹配method
 * @param args
 * @param method
 * @param options
 */
var doMethod = function(args, method, options){
  "use strict";
  var url = args[0]
    , router = options.router
    , rules = options.rules || []
    , rule
    , len = rules.length
    , templateUrl = '';

  if(typeof url !== 'string')
    throw new Error('miss url !');
  if(!util.isArray(rules)){
    throw new Error('options.middleware should be a Array!');
  }

  while (len > 0){
    len -= 1;
    rule = rules[len];
    templateUrl = rule.url;
    if(templateUrl.indexOf('\\') == 0){
      new RegExp(templateUrl.substring(1), 'i').test(url) && insertMiddleware(args, rule.fn);
    }else{
      (templateUrl === url) && insertMiddleware(args, rule.fn);
    }
  }

  router[method].apply(router, args);
};

BaseRouter.prototype.init = function(options){
  "use strict";
  METHOD.forEach(function(method){
    "use strict";
    BaseRouter.prototype[method] = function(){
      doMethod(Array.prototype.slice.call(arguments), method, options);
    };
  });
};

<commit_msg>add ignore<commit_after>/**
 * Created by menzhongxin on 2016/10/26.
 */
var METHOD = ['get', 'post', 'put', 'delete']
  , util = require('./utils.js');

var BaseRouter = function(){};
module.exports = new BaseRouter();

/**
 * 迭代在路由头部插入中间件,按照中间件的顺序添加
 * @param args
 * @param middleware
 */
var insertMiddleware = function(args, middleware){
  "use strict";
  !util.isArray(middleware) && (middleware = [middleware]);
  for(var i = 0; i < middleware.length; i ++) {
    args.splice(i + 1, 0, middleware[i]);
  }
};

/**
 * 匹配method
 * @param args
 * @param method
 * @param options
 */
var doMethod = function(args, method, options){
  "use strict";
  var url = args[0]
    , router = options.router
    , rules = options.rules || []
    , rule
    , len = rules.length
    , templateUrl = '';

  if(typeof url !== 'string')
    throw new Error('miss url !');
  if(!util.isArray(rules)){
    throw new Error('options.rules should be a Array!');
  }

  while (len > 0){
    len -= 1;
    rule = rules[len];
    templateUrl = rule.url;
    if(templateUrl.indexOf('\\') == 0){
      new RegExp(templateUrl.substring(1), 'i').test(url) && insertMiddleware(args, rule.fn);
    }else{
      (templateUrl === url) && insertMiddleware(args, rule.fn);
    }
  }

  router[method].apply(router, args);
};

BaseRouter.prototype.init = function(options){
  "use strict";
  METHOD.forEach(function(method){
    "use strict";
    BaseRouter.prototype[method] = function(){
      doMethod(Array.prototype.slice.call(arguments), method, options);
    };
  });
};

<|endoftext|>


<commit_before>
init.add(function () {

	// Threads

	window.post = {};

	post.initThreadList = function () {
// TODO: 최근글 하일라이트
//				CharSequence titleCss = "thread" +
//					(thread.getUdate().getMillis() > authService.getLastVisit().getMillis() ? " tn" : "") +
//					(thread.getId() == postContext.getParam().getThreadId() ? " tc" : "");

	}

	post.initThreadAndPosts = function () {

		var patterns = [
			{	// iframe
				pattern: /(<iframe.+?\/iframe>)/gim,
				replace: '$1'
			},
			{	// object
				pattern: /(<object.+?\/object>)/gim,
				replace: '$1'
			},
			{	// embed
				pattern: /((?:<embed.+?>|<\/embed>)+)/gim,
				replace: '$1'
			},
			{
				// img
				pattern: /(<img\s.+?>)/gi,
				replace: '$1'
			},
			{	// img url
				pattern: /(https?:\/\/[^ "'<>\n\r\)]+\.(jpg|jpeg|gif|png))(?=[\n ])/ig,
				replace: '$1'
			},
			{	// url
				pattern: /(https?:\/\/[^ "'>)]+)/g,
				replace: '$1'
			}
		];

		var $1pat = /\$1/g;

		function tagUp(s, pi) {
			if (pi == patterns.length) {
				return s;
			}
			var p = patterns[pi];
			var r = '';
			var a = 0;
			var match;
			while(match = p.pattern.exec(s)) {
				r += tagUp(s.slice(a, match.index), pi + 1);
				r += p.replace.replace($1pat, match[1]);
				a = match.index + match[0].length;
			}
			r += tagUp(s.slice(a), pi + 1);
			return r;
		}

		var $posts = $('#posts');

		$posts.find('.text pre').each(function () {
			$(this).html(tagUp($(this).html(), 0));
		});

		function handle() {
			return $('<button class="media-handle btn btn-mini btn-info">Show</button>');
		}

		$posts.find('.media-img').after(
			handle().click(function () {
				var $handle = $(this);
				var $media = $handle.prev();
				if ($handle.text() === 'Show') {
					$handle.after(
						$('

').append(
							$('', { src: $media.children('a').attr('href') })
						)
					);
					$handle.text('Hide');
				} else {
					$handle.next().remove();
					$handle.text('Show');
				}
			})
		);

		$posts.find('.media').after(
			handle().click(function () {
				var $handle = $(this);
				var $media = $handle.prev();
				if ($handle.text() === 'Show') {
					$handle.data("org-code", $media.text());
					$media.html($media.text());
					$handle.text('Hide');
				} else {
					$media.text($handle.data("org-code"));
					$handle.text('Show');
				}
			})
		);
	};

	// for files

	jQuery.fn.faActivateAttachURL = function() {
		return $(this).each(function() {
			var url = $.trim($(this).text())
			var nameIndex = url.lastIndexOf("/")
			var baseURL = url.substring(0, nameIndex)
			var fileName = url.substring(nameIndex + 1)
			var encodedFileName = encodeURIComponent(fileName)
			$(this).html(
				/.*\.(jpg|jpeg|gif|png)$/i.test(fileName) ?
					'' + fileName + ''	 :
					'' + fileName + ''
			).faAttachGo()
		})
	}

	/*

		jQuery.fn.attachScroller = function(callback) {
			var target = this;
			var y = 0;
			var ny = 0;
			var timer = null;

			function scroll() {
				var scrollTop = document.documentElement.scrollTop + document.body.scrollTop;
				var dy = y - scrollTop;
				var ay = Math.max(Math.abs(Math.round(dy * 0.15)), 1) * (dy < 0 ? -1 : 1);
				clearTimeout(timer);
				if (Math.abs(dy) > 3 && Math.abs(ny - scrollTop) < 3) {
					ny = scrollTop + ay;
					scrollTo(0, ny);
					timer = setTimeout(scroll, 10);
				} else {
					if (callback) callback();
				}
			}

			var viewportHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight;
			y = target.offset().top;
			y = y - (viewportHeight / 4);
			y = Math.round(Math.max(y, 0));
			timer = setTimeout(scroll, 0);
		}

		function initPostView() {
			//$(".text").faStripPre();
			$(".files .file").faActivateAttachURL();
			$(".text").faActivateURL();
		}

		function initPostViewScroller(lastVisit) {
			var target = null;
			$(".posts .cdate").each(function(i) {
				if (this.innerHTML > lastVisit) {
					target = this;
					return false;
				}
			})
			if (target) $(target).attachScroller()
		}

	*/

	function initInputFile() {
		var fileCount = 0;

		function addFileInputTag() {
			fileCount++;
			$("#file").append("<input type=\"file\" name=\"file\" id=\"file" + fileCount + "\" class=\"file\" multiple=\"multiple\"/>
");

			if (fileCount >= 32) {
				$("#addFile").parent("div").hide();
			}
		}

		addFileInputTag();
		$("#addFile").click(function(event) {
			event.preventDefault();
			addFileInputTag();
		});
	}

	post.initNewForm = function () {
		var $form = $('#new-form');
		var $category = $form.find('[name=category]');
		var $writer = $form.find('[name=writer]');
		var $title = $form.find('[name=title]');
		var sender = new Sender($form);

		if (url.query.c) {
			$category.val(url.query.c);
		}
		restoreWriter($writer);
		if ($writer.val()) {
			$title.focus();
		} else {
			$writer.focus();
		}
		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function () {
				saveWriter($writer);
				location = '/threads';
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	post.initReplyForm = function () {
		var $form = $('#reply-form');
		var $writer = $form.find('[name=writer]');
		var sender = new Sender($form);

		restoreWriter($writer);
		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function (body) {
				saveWriter($writer);
				location = '/threads/' + body.tid;
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	post.initEditForm = function () {
		var $form = $('#edit-form');
		var sender = new Sender($form);

		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function () {
				location = '/threads/' + url.pathnames[1];
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	function saveWriter($writer) {
		localStorage.setItem('writer', $writer.val());
	}

	function restoreWriter($writer) {
		$writer.val(localStorage.getItem('writer') || '');
	}

	function ajaxFormSuccess($form, next) {
		return function (body) {
			var err = body.err;
			if (err && err.rc === error.INVALID_DATA) {
				alerts.fill($form, err.fields);
				return;
			}
			if (err) {
				showError.system(body.err);
				return;
			}
			next(body);
		};
	}

	function ajaxFormError(xhr, textStatus, errorThrown) {
		var message = textStatus || errorThrown || 'Unknown Error';
		showError.system({ message: message });
	}

});
<commit_msg>url tagging bug fixed.<commit_after>
init.add(function () {

	// Threads

	window.post = {};

	post.initThreadList = function () {
// TODO: 최근글 하일라이트
//				CharSequence titleCss = "thread" +
//					(thread.getUdate().getMillis() > authService.getLastVisit().getMillis() ? " tn" : "") +
//					(thread.getId() == postContext.getParam().getThreadId() ? " tc" : "");

	}

	post.initThreadAndPosts = function () {

		var patterns = [
			{	// iframe
				pattern: /(<iframe.+?\/iframe>)/gim,
				replace: '$1'
			},
			{	// object
				pattern: /(<object.+?\/object>)/gim,
				replace: '$1'
			},
			{	// embed
				pattern: /((?:<embed.+?>|<\/embed>)+)/gim,
				replace: '$1'
			},
			{
				// img
				pattern: /(<img\s.+?>)/gi,
				replace: '$1'
			},
			{	// img url
				pattern: /(https?:\/\/[^ "'<>\n\r\)]+\.(jpg|jpeg|gif|png))(?=[\n ])/ig,
				replace: '$1'
			},
			{	// url
				pattern: /(https?:\/\/[^ "'>)\n\r]+)/g,
				replace: '$1'
			}
		];

		var $1pat = /\$1/g;

		function tagUp(s, pi) {
			if (pi == patterns.length) {
				return s;
			}
			var p = patterns[pi];
			var r = '';
			var a = 0;
			var match;
			while(match = p.pattern.exec(s)) {
				r += tagUp(s.slice(a, match.index), pi + 1);
				r += p.replace.replace($1pat, match[1]);
				a = match.index + match[0].length;
			}
			r += tagUp(s.slice(a), pi + 1);
			return r;
		}

		var $posts = $('#posts');

		$posts.find('.text pre').each(function () {
			$(this).html(tagUp($(this).html(), 0));
		});

		function handle() {
			return $('<button class="media-handle btn btn-mini btn-info">Show</button>');
		}

		$posts.find('.media-img').after(
			handle().click(function () {
				var $handle = $(this);
				var $media = $handle.prev();
				if ($handle.text() === 'Show') {
					$handle.after(
						$('

').append(
							$('', { src: $media.children('a').attr('href') })
						)
					);
					$handle.text('Hide');
				} else {
					$handle.next().remove();
					$handle.text('Show');
				}
			})
		);

		$posts.find('.media').after(
			handle().click(function () {
				var $handle = $(this);
				var $media = $handle.prev();
				if ($handle.text() === 'Show') {
					$handle.data("org-code", $media.text());
					$media.html($media.text());
					$handle.text('Hide');
				} else {
					$media.text($handle.data("org-code"));
					$handle.text('Show');
				}
			})
		);
	};

	// for files

	jQuery.fn.faActivateAttachURL = function() {
		return $(this).each(function() {
			var url = $.trim($(this).text())
			var nameIndex = url.lastIndexOf("/")
			var baseURL = url.substring(0, nameIndex)
			var fileName = url.substring(nameIndex + 1)
			var encodedFileName = encodeURIComponent(fileName)
			$(this).html(
				/.*\.(jpg|jpeg|gif|png)$/i.test(fileName) ?
					'' + fileName + ''	 :
					'' + fileName + ''
			).faAttachGo()
		})
	}

	/*

		jQuery.fn.attachScroller = function(callback) {
			var target = this;
			var y = 0;
			var ny = 0;
			var timer = null;

			function scroll() {
				var scrollTop = document.documentElement.scrollTop + document.body.scrollTop;
				var dy = y - scrollTop;
				var ay = Math.max(Math.abs(Math.round(dy * 0.15)), 1) * (dy < 0 ? -1 : 1);
				clearTimeout(timer);
				if (Math.abs(dy) > 3 && Math.abs(ny - scrollTop) < 3) {
					ny = scrollTop + ay;
					scrollTo(0, ny);
					timer = setTimeout(scroll, 10);
				} else {
					if (callback) callback();
				}
			}

			var viewportHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight;
			y = target.offset().top;
			y = y - (viewportHeight / 4);
			y = Math.round(Math.max(y, 0));
			timer = setTimeout(scroll, 0);
		}

		function initPostView() {
			//$(".text").faStripPre();
			$(".files .file").faActivateAttachURL();
			$(".text").faActivateURL();
		}

		function initPostViewScroller(lastVisit) {
			var target = null;
			$(".posts .cdate").each(function(i) {
				if (this.innerHTML > lastVisit) {
					target = this;
					return false;
				}
			})
			if (target) $(target).attachScroller()
		}

	*/

	function initInputFile() {
		var fileCount = 0;

		function addFileInputTag() {
			fileCount++;
			$("#file").append("<input type=\"file\" name=\"file\" id=\"file" + fileCount + "\" class=\"file\" multiple=\"multiple\"/>
");

			if (fileCount >= 32) {
				$("#addFile").parent("div").hide();
			}
		}

		addFileInputTag();
		$("#addFile").click(function(event) {
			event.preventDefault();
			addFileInputTag();
		});
	}

	post.initNewForm = function () {
		var $form = $('#new-form');
		var $category = $form.find('[name=category]');
		var $writer = $form.find('[name=writer]');
		var $title = $form.find('[name=title]');
		var sender = new Sender($form);

		if (url.query.c) {
			$category.val(url.query.c);
		}
		restoreWriter($writer);
		if ($writer.val()) {
			$title.focus();
		} else {
			$writer.focus();
		}
		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function () {
				saveWriter($writer);
				location = '/threads';
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	post.initReplyForm = function () {
		var $form = $('#reply-form');
		var $writer = $form.find('[name=writer]');
		var sender = new Sender($form);

		restoreWriter($writer);
		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function (body) {
				saveWriter($writer);
				location = '/threads/' + body.tid;
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	post.initEditForm = function () {
		var $form = $('#edit-form');
		var sender = new Sender($form);

		$form.ajaxForm({
			dataType: 'json',
			beforeSend: function () {
				alerts.clear($form);
				sender.beforeSend();
			},
			success: ajaxFormSuccess($form, function () {
				location = '/threads/' + url.pathnames[1];
			}),
			error: ajaxFormError,
			complete: sender.complete
		});
	};

	function saveWriter($writer) {
		localStorage.setItem('writer', $writer.val());
	}

	function restoreWriter($writer) {
		$writer.val(localStorage.getItem('writer') || '');
	}

	function ajaxFormSuccess($form, next) {
		return function (body) {
			var err = body.err;
			if (err && err.rc === error.INVALID_DATA) {
				alerts.fill($form, err.fields);
				return;
			}
			if (err) {
				showError.system(body.err);
				return;
			}
			next(body);
		};
	}

	function ajaxFormError(xhr, textStatus, errorThrown) {
		var message = textStatus || errorThrown || 'Unknown Error';
		showError.system({ message: message });
	}

});
<|endoftext|>


<commit_before>'use strict';

var argv = require('yargs').argv,
    gulp = require('gulp'),
//  debug = require('gulp-debug'),
    util = require('gulp-util'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    jshint = require('gulp-jshint'),
    handlebars = require('gulp-ember-handlebars'),
    bower = require('gulp-bower'),
    browserify = require('browserify'),
    livereload = require('gulp-livereload'),
    source = require('vinyl-source-stream'),
    streamify = require('gulp-streamify'),
    less = require('gulp-less');

var paths = {
    serverJavaScripts: [
        'gulpfile.js',
        'server/**/*.js',
        '!server/public/vendor/**/*.js',
        '!server/public/libs/**/*.js',
        'migration/**/*.js'
    ],
    clientJavaScripts: [
        'app/**/*.js',
        '!app/dist/*.js',
        '!app/tests/**/*', // TBD Remove eventually
        '!app/tests/vendor/**/*.js'
    ],
    clientTemplates: [
        'app/templates/**/*.hbs'
    ],
    clientCSS: [
        'app/stylesheets/**/*.less'
    ],
    clientLibs: [
        'momentjs/moment.js',
        'uri.js/src/IPv6.js',
        'uri.js/src/punycode.js',
        'uri.js/src/SecondLevelDomains.js',
        'uri.js/src/URI.js',
        'jquery/dist/jquery.js',
        'jquery-cookie/jquery.cookie.js',
        'eventie/eventie.js',
        'eventEmitter/EventEmitter.js',
        'imagesloaded/imagesloaded.js',
        'bootstrap/dist/js/bootstrap.js',
        'handlebars/handlebars.js',
        'ember/ember.js',
        'TitleNotifier.js/title_notifier.js',
        'howler/howler.js',
        'jquery.atwho/dist/js/jquery.atwho.js',
        'Caret.js/dist/jquery.caret.min.js',
        'emojify.js/emojify.js'
    ],
    testJavaScripts: [
        'test/acceptance/**/*.js'
    ]
};

paths.clientLibs = paths.clientLibs.map(function(elem) { return 'server/public/vendor/' + elem; });

function handleError(err) {
    /* jshint validthis: true */
    util.log(util.colors.red(err.toString()));
    util.beep();
    this.emit('end');
}

gulp.task('jshint', function() {
    return gulp.src(paths.serverJavaScripts
        .concat(paths.clientJavaScripts)
        .concat(paths.testJavaScripts))
        .pipe(jshint())
        .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('bower', function() {
    return bower('./server/public/vendor');
});

gulp.task('templates', function(){
    return gulp.src(paths.clientTemplates)
        .pipe(handlebars({
            outputType: 'cjs'
        }))
        .pipe(concat('templates.js'))
        .pipe(gulp.dest('./app/dist/'))
        .pipe(livereload());
});

gulp.task('browserify', ['templates'], function() {
    return browserify('./app/js/app.js')
        .bundle({
            debug: true
        })
        .on('error', handleError)
        .pipe(source('app.js'))
        .pipe(argv.prod ? streamify(uglify()) : util.noop())
        .pipe(gulp.dest('./app/dist'))
        .pipe(livereload());
});

gulp.task('libs', ['bower'], function() {
    return gulp.src(paths.clientLibs)
        .pipe(concat('libs.js'))
        .pipe(argv.prod ? uglify() : util.noop())
        .pipe(gulp.dest('./app/dist'))
        .pipe(livereload());
});

gulp.task('less', ['bower'], function () {
    gulp.src('./app/stylesheets/app.less')
        .pipe(less())
        .pipe(gulp.dest('./app/dist/'))
        .pipe(livereload());
});

gulp.task('watch', function() {
    gulp.watch(paths.clientTemplates, ['browserify']);
    gulp.watch(paths.clientJavaScripts, ['browserify']);
    gulp.watch(paths.clientCSS, ['less']);
});

// The default task
gulp.task('default', ['jshint']);

gulp.task('all', ['browserify', 'libs', 'less']);
<commit_msg>Disable livereload for now<commit_after>'use strict';

var argv = require('yargs').argv,
    gulp = require('gulp'),
//  debug = require('gulp-debug'),
    util = require('gulp-util'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    jshint = require('gulp-jshint'),
    handlebars = require('gulp-ember-handlebars'),
    bower = require('gulp-bower'),
    browserify = require('browserify'),
//  livereload = require('gulp-livereload'),
    source = require('vinyl-source-stream'),
    streamify = require('gulp-streamify'),
    less = require('gulp-less');

var paths = {
    serverJavaScripts: [
        'gulpfile.js',
        'server/**/*.js',
        '!server/public/vendor/**/*.js',
        '!server/public/libs/**/*.js',
        'migration/**/*.js'
    ],
    clientJavaScripts: [
        'app/**/*.js',
        '!app/dist/*.js',
        '!app/tests/**/*', // TBD Remove eventually
        '!app/tests/vendor/**/*.js'
    ],
    clientTemplates: [
        'app/templates/**/*.hbs'
    ],
    clientCSS: [
        'app/stylesheets/**/*.less'
    ],
    clientLibs: [
        'momentjs/moment.js',
        'uri.js/src/IPv6.js',
        'uri.js/src/punycode.js',
        'uri.js/src/SecondLevelDomains.js',
        'uri.js/src/URI.js',
        'jquery/dist/jquery.js',
        'jquery-cookie/jquery.cookie.js',
        'eventie/eventie.js',
        'eventEmitter/EventEmitter.js',
        'imagesloaded/imagesloaded.js',
        'bootstrap/dist/js/bootstrap.js',
        'handlebars/handlebars.js',
        'ember/ember.js',
        'TitleNotifier.js/title_notifier.js',
        'howler/howler.js',
        'jquery.atwho/dist/js/jquery.atwho.js',
        'Caret.js/dist/jquery.caret.min.js',
        'emojify.js/emojify.js'
    ],
    testJavaScripts: [
        'test/acceptance/**/*.js'
    ]
};

paths.clientLibs = paths.clientLibs.map(function(elem) { return 'server/public/vendor/' + elem; });

function handleError(err) {
    /* jshint validthis: true */
    util.log(util.colors.red(err.toString()));
    util.beep();
    this.emit('end');
}

gulp.task('jshint', function() {
    return gulp.src(paths.serverJavaScripts
        .concat(paths.clientJavaScripts)
        .concat(paths.testJavaScripts))
        .pipe(jshint())
        .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('bower', function() {
    return bower('./server/public/vendor');
});

gulp.task('templates', function(){
    return gulp.src(paths.clientTemplates)
        .pipe(handlebars({
            outputType: 'cjs'
        }))
        .pipe(concat('templates.js'))
        .pipe(gulp.dest('./app/dist/'));
});

gulp.task('browserify', ['templates'], function() {
    return browserify('./app/js/app.js')
        .bundle({
            debug: true
        })
        .on('error', handleError)
        .pipe(source('app.js'))
        .pipe(argv.prod ? streamify(uglify()) : util.noop())
        .pipe(gulp.dest('./app/dist'));
});

gulp.task('libs', ['bower'], function() {
    return gulp.src(paths.clientLibs)
        .pipe(concat('libs.js'))
        .pipe(argv.prod ? uglify() : util.noop())
        .pipe(gulp.dest('./app/dist'));
});

gulp.task('less', ['bower'], function () {
    gulp.src('./app/stylesheets/app.less')
        .pipe(less())
        .pipe(gulp.dest('./app/dist/'));
});

gulp.task('watch', function() {
    gulp.watch(paths.clientTemplates, ['browserify']);
    gulp.watch(paths.clientJavaScripts, ['browserify']);
    gulp.watch(paths.clientCSS, ['less']);
});

// The default task
gulp.task('default', ['jshint']);

gulp.task('all', ['browserify', 'libs', 'less']);
<|endoftext|>


<commit_before>'use strict'

var gulp = require('gulp')
var del = require('del')
var rename = require('gulp-rename')
var transpiler = require('./lib/transpilation/transpiler.js')

// Config for paths
var paths = {
  assets: 'app/assets/',
  assets_scss: 'app/assets/scss/',
  dist: 'dist/',
  templates: 'app/templates/',
  npm: 'node_modules/',
  prototype_scss: 'node_modules/@gemmaleigh/prototype-scss-refactor/**/*.scss' // This can be removed later
}

var transpileRunner = function (templateLanguage) {
  return gulp.src(paths.templates + 'govuk_template.html')
    .pipe(transpiler(templateLanguage))
    .pipe(rename({extname: '.html.' + templateLanguage}))
    .pipe(gulp.dest(paths.dist))
}

// Setup tasks
// Copy prototype-scss-refactor into app/assets/scss
// This step can be removed later once these files exist here
gulp.task('copy:prototype-scss-refactor', function () {
  gulp.src(paths.prototype_scss)
    .pipe(gulp.dest(paths.assets_scss))
})

gulp.task('clean', function () {
  return del([paths.dist + '*'])
})

gulp.task('transpile', ['transpile:nunjucks', 'transpile:erb', 'transpile:handlebars', 'transpile:django'])
gulp.task('transpile:nunjucks', function () {
  return gulp.src(paths.templates + 'govuk_template.html')
    .pipe(rename({extname: '.html.nunjucks'}))
    .pipe(gulp.dest(paths.dist))
})
gulp.task('transpile:erb', transpileRunner.bind(null, 'erb'))
gulp.task('transpile:handlebars', transpileRunner.bind(null, 'handlebars'))
gulp.task('transpile:django', transpileRunner.bind(null, 'django'))
<commit_msg>Tidy up the gulpfile a bit<commit_after>'use strict'

const gulp = require('gulp')
const del = require('del')
const rename = require('gulp-rename')
const transpiler = require('./lib/transpilation/transpiler.js')

// Config for paths
const paths = {
  assets: 'app/assets/',
  assets_scss: 'app/assets/scss/',
  dist: 'dist/',
  templates: 'app/templates/',
  npm: 'node_modules/',
  prototype_scss: 'node_modules/@gemmaleigh/prototype-scss-refactor/**/*.scss' // This can be removed later
}

// Task for cleaning the distribution
gulp.task('clean', () => {
  return del([paths.dist + '*'])
})

// Task for copying the assets
gulp.task('copy:prototype-scss-refactor', () => {
  gulp.src(paths.prototype_scss)
    .pipe(gulp.dest(paths.assets_scss))
})

// Task for transpiling the templates
let transpileRunner = templateLanguage => {
  return gulp.src(paths.templates + 'govuk_template.html')
    .pipe(transpiler(templateLanguage))
    .pipe(rename({extname: '.html.' + templateLanguage}))
    .pipe(gulp.dest(paths.dist))
}
gulp.task('transpile', ['transpile:nunjucks', 'transpile:erb', 'transpile:handlebars', 'transpile:django'])
gulp.task('transpile:nunjucks', () => {
  return gulp.src(paths.templates + 'govuk_template.html')
    .pipe(rename({extname: '.html.nunjucks'}))
    .pipe(gulp.dest(paths.dist))
})
gulp.task('transpile:erb', transpileRunner.bind(null, 'erb'))
gulp.task('transpile:handlebars', transpileRunner.bind(null, 'handlebars'))
gulp.task('transpile:django', transpileRunner.bind(null, 'django'))
<|endoftext|>


<commit_before>var isJSON = function(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
};

var deepmerge = function(obj1, obj2) {
    for (var object2 in obj2) {
        var value = obj2[object2];
        if (object2 in obj1) {
            if (typeof value == "object") {
                deepmerge(obj1[object2], value);
            } else {
                obj1[object2] = value;
            }
        } else {
            obj1[object2] = value;
        }
    }
    return obj1;
};

var merge = function(defaults, config) {
    var defobj = {};
    var confobj = {};
    for (var attr in defaults) {
        if (defaults.hasOwnProperty(attr))
            unpack(defobj, attr, defaults[attr]);
    }
    for (attr in config) {
        if (config.hasOwnProperty(attr))
            unpack(confobj, attr, config[attr]);
    }

    return deepmerge(defobj, confobj);
};

var unpack = function(obj, str, value) {
    var split = str.split(".");
    var lobj = obj;
    for (var current in split) {
        if (split.hasOwnProperty(current)) {
            var curv = split[current];      //Real objects have curvs
            if (!(curv in lobj && typeof lobj[curv] == "object")) {
                lobj[curv] = {};
            }
            if (current == split.length - 1) {
                lobj[curv] = value;
            }
            lobj = lobj[curv];
        }
    }
};

var parse = function(str_defaults, str_config) {
    return merge(
        isJSON(str_defaults) ? JSON.parse(str_defaults) : {},
        isJSON(str_config) ? JSON.parse(str_config) : {});
};

var toJSON = function(obj) {
    return JSON.stringify(obj, null, 4);
};

var postProcess = function(str) {
    var reg = /\$\{([^\{^\}]*)\}/g;
    return str.replace(reg, function(full_match, words) {
        return eval(words);
    });
};<commit_msg>Escape inlines properly<commit_after>var isJSON = function(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
};

var deepmerge = function(obj1, obj2) {
    for (var object2 in obj2) {
        var value = obj2[object2];
        if (object2 in obj1) {
            if (typeof value == "object") {
                deepmerge(obj1[object2], value);
            } else {
                obj1[object2] = value;
            }
        } else {
            obj1[object2] = value;
        }
    }
    return obj1;
};

var merge = function(defaults, config) {
    var defobj = {};
    var confobj = {};
    for (var attr in defaults) {
        if (defaults.hasOwnProperty(attr))
            unpack(defobj, attr, defaults[attr]);
    }
    for (attr in config) {
        if (config.hasOwnProperty(attr))
            unpack(confobj, attr, config[attr]);
    }

    return deepmerge(defobj, confobj);
};

var unpack = function(obj, str, value) {
    var split = str.split(".");
    var lobj = obj;
    for (var current in split) {
        if (split.hasOwnProperty(current)) {
            var curv = split[current];      //Real objects have curvs
            if (!(curv in lobj && typeof lobj[curv] == "object")) {
                lobj[curv] = {};
            }
            if (current == split.length - 1) {
                lobj[curv] = value;
            }
            lobj = lobj[curv];
        }
    }
};

var parse = function(str_defaults, str_config) {
    return merge(
        isJSON(str_defaults) ? JSON.parse(str_defaults) : {},
        isJSON(str_config) ? JSON.parse(str_config) : {});
};

var toJSON = function(obj) {
    return JSON.stringify(obj, null, 4);
};

//var postProcess = function(str) {
//    var reg = /\$\{([^\{^\}]*)\}/g;
//    return str.replace(reg, function(full_match, words) {
//        return eval(words);
//    });
//};

var postProcess = function(str) {
    var build = [];
    for (var i = 0; i < str.length; i++) {
        var char = str[i];
        var prevchar = i === 0 ? "" : str[i - 1];
        if (char == "$" && str.length-1 != i) {
            if (prevchar == "\\") {build.pop(); build.push(char); continue;}
            var nchar = str[++i];
            if (nchar == "{") {
                var q = false, bl = 1;
                var jsbuild = "";
                while (bl > 0 && i < str.length) {
                    var newchar = str[++i];
                    switch (newchar) {
                        case "{": if (!q) bl++; jsbuild += newchar; break;
                        case "}": if (!q) bl--; if (bl!==0) jsbuild += newchar; break;
                        case "\"": q = !q; jsbuild += newchar; break;
                        default: jsbuild += newchar; break;
                    }
                }
                build.push(eval(jsbuild));
            }
        } else {
            build.push(char);
        }
    }
    return build.join("");
};<|endoftext|>


<commit_before>var express = require('express')
,   config  = require('config')
,   url     = require('url')
,   util    = require('util')
,   models  = require('./models')
,   fs      = require('fs')
,   Walk    = models.sequelize.models.walks
,   Area    = models.sequelize.models.areas;

/*
* GET home page.
*/

var router = express.Router();
module.exports = router;

router.get('/version', function(req, res){
    fs.readFile('package.json', function (err, data) {
        var json = JSON.parse(data);
        res.json({
            app_version: json.version,
            app_env: process.env.NODE_ENV,
            twitter_hashtags: config.twitter_hashtags
        });
    });
});

router.get('/search', function(req, res){
    var order_hash = {
        "newest_first"       : "date desc",
        "oldest_first"       : "date",
        "longest_first"      : "length desc",
        "shortest_first"     : "length",
        "easternmost_first"  : "xmax(PATH) desc",
        "westernmost_first"  : "xmin(PATH)",
        "southernmost_first" : "ymin(PATH)",
        "northernmost_first" : "ymax(PATH) desc",
        "nearest_first"      : "distance"
    };
    var where, exprs = [], values = [];
    var order = order_hash[req.query.order] || 'date desc';

    var attributes = ['id', 'date', 'title', 'comment', 'path', "length"];

    if (req.query.id) {
        exprs.push('id = ?');
        values.push(req.query.id);
    }
    else if (req.query.date) {
        exprs.push('date = ?');
        values.push(req.query.date);
    }
    else {
        if (req.query.year) {
            exprs.push('extract(year from DATE) = ?');
            values.push(parseInt(req.query.year));
        }
        if (req.query.month) {
            exprs.push('extract(month from DATE) = ?');
            values.push(parseInt(req.query.month));
        }

        if (req.query.filter == 'neighborhood') {
            var latitude  = parseFloat(req.query.latitude);
            var longitude = parseFloat(req.query.longitude);
            var radius    = parseFloat(req.query.radius);
            var dlat      = radius*180/Math.PI/models.EARTH_RADIUS;
            var mlat      = latitude > 0 ? latitude + dlat : latitude - dlat;
            var dlon      = dlat/Math.cos(mlat/180*Math.PI);
            var center    = Walk.getPoint(longitude, latitude);
            var lb        = Walk.getPoint(longitude-dlon, latitude-dlat);
            var rt        = Walk.getPoint(longitude+dlon, latitude+dlat);
            attributes.push([ util.format("st_distance(path, '%s', true)/1000", center), 'distance' ]);
            exprs.push('st_makebox2d(?, ?) && path', 'st_distance(path, ?, TRUE) <= ?');
            values.push(lb, rt,  center, radius);
        }
        else if (req.query.filter == 'cities') {
            var cities = req.query.cities.split(/,/).map(function (elm) { return "'" + elm + "'"; }).join(',');
            exprs.push("EXISTS (SELECT * FROM areas WHERE jcode IN (" + cities + ") AND path && the_geom AND ST_Intersects(path, the_geom))");
        }
        else if (req.query.filter == 'crossing') {
            var linestring = Walk.decodePath(req.query.searchPath);
            exprs.push("path && ?", "ST_Intersects(path, ?)");
            values.push(linestring, linestring);
        }
        else if (req.query.filter == 'hausdorff') {
            var max_distance = req.query.max_distance || 4000;
            linestring = Walk.decodePath(req.query.searchPath);
            extent     = Walk.getPathExtent(req.query.searchPath);
            dlat       = max_distance*180/Math.PI/models.EARTH_RADIUS;
            mlat       = Math.max(Math.abs(extent.ymax + dlat), Math.abs(extent.ymin-dlat));
            dlon       = dlat/Math.cos(mlat/180*Math.PI);
            lb         = Walk.getPoint(extent.xmin-dlon, extent.ymin-dlat);
            rt         = Walk.getPoint(extent.xmax+dlon, extent.ymax+dlat);

            attributes.push([util.format("ST_HausdorffDistance(ST_Transform(path, %d), ST_Transform('%s', %d))/1000", models.SRID_FOR_SIMILAR_SEARCH, linestring, models.SRID_FOR_SIMILAR_SEARCH), 'distance']);
            exprs.push('ST_Within(path, ST_SetSRID(ST_MakeBox2d(?, ?), ?))',
                'ST_HausdorffDistance(ST_Transform(path, ?), ST_Transform(?, ?)) < ?');
            values.push(lb, rt, models.SRID, models.SRID_FOR_SIMILAR_SEARCH, linestring, models.SRID_FOR_SIMILAR_SEARCH, max_distance);
        }
    }
    where = [exprs.map(function (e) { return '(' + e + ')';}).join(' AND ')].concat(values);
    var limit  = parseInt(req.query.limit) || 20;
    var offset = parseInt(req.query.offset) || 0;
    Walk.findAndCountAll({
        attributes : attributes,
        order  : order,
        where  : where,
        offset : offset,
        limit  : limit
    }).then(function ( result) {
        var params = null;
        if (result.count > offset + limit) {
            var q = Object.keys(req.query).filter(function (e) { return e != 'offset';}).map( function (e) { return e + '=' + req.query[e]; });
            q.push("offset=" +  (offset + limit));
            params = q.join('&');
        }
        res.json({
            count: result.count,
            params: params,
            rows:  result.rows.map(function (row) { return row.asObject(true); })
        });
    });
});

router.get('/add_city', function(req, res){
    var latitude  = parseFloat(req.query.latitude);
    var longitude = parseFloat(req.query.longitude);
    Area.find({
        where  : ['ST_Contains(the_geom, ST_SetSRID(ST_Point(?, ?), ?))', longitude, latitude, models.SRID],
    }).then(function (result) {
        res.json(result.asObject());
    });
});

router.post('/save', function(req, res) {
    var walk;
    var saveCallback = function (row) {
        res.json(row.asObject());
    };
    var linestring = req.body.path ? Walk.decodePath(req.body.path) : null;
    var query;
    var values;
    if (req.body.id) {
        if (linestring) {
            query = "UPDATE walks SET date = ?, title = ?, \"comment\" = ?, path = ?, length = ST_LENGTH(?, TRUE)/1000, updated_at = NOW() WHERE id = ? RETURNING *";
            values = [req.body.date, req.body.title, req.body.comment, linestring, linestring, req.body.id];
        }
        else {
            query = "UPDATE walks SET date = ?, title = ?, \"comment\" = ?, updated_at = NOW() WHERE id = ? RETURNING *";
            values = [req.body.date, req.body.title, req.body.comment, req.body.id];
        }
    }
    else {
        query = "INSERT INTO walks (date, title, \"comment\", path, length, created_at, updated_at) VALUES(?, ?, ?, ?, ST_LENGTH(?, TRUE)/1000, NOW(), NOW()) RETURNING *";
        values = [req.body.date, req.body.title, req.body.comment, linestring, linestring];
    }
    models.sequelize.query(query, {model: Walk, raw : true, replacements: values}).then(function (row) {
        res.json(row);
    });

});

router.get('/destroy/:id', function(req, res) {
    Walk.destroy({where : { id : req.params.id } }).then(function () {
        res.end('');
    });
});

router.get('/export/:id', function(req, res) {
    Walk.find({id : req.params.id }).then(function (row) {
        res.type('application/json');
        res.attachment(req.params.id + ".json");
        res.json(row.pathJSON());
    });
});
<commit_msg>for new postgis versions<commit_after>var express = require('express')
,   config  = require('config')
,   url     = require('url')
,   util    = require('util')
,   models  = require('./models')
,   fs      = require('fs')
,   Walk    = models.sequelize.models.walks
,   Area    = models.sequelize.models.areas;

/*
* GET home page.
*/

var router = express.Router();
module.exports = router;

router.get('/version', function(req, res){
    fs.readFile('package.json', function (err, data) {
        var json = JSON.parse(data);
        res.json({
            app_version: json.version,
            app_env: process.env.NODE_ENV,
            twitter_hashtags: config.twitter_hashtags
        });
    });
});

router.get('/search', function(req, res){
    var order_hash = {
        "newest_first"       : "date desc",
        "oldest_first"       : "date",
        "longest_first"      : "length desc",
        "shortest_first"     : "length",
        "easternmost_first"  : "st_xmax(PATH) desc",
        "westernmost_first"  : "st_xmin(PATH)",
        "southernmost_first" : "st_ymin(PATH)",
        "northernmost_first" : "st_ymax(PATH) desc",
        "nearest_first"      : "distance"
    };
    var where, exprs = [], values = [];
    var order = order_hash[req.query.order] || 'date desc';

    var attributes = ['id', 'date', 'title', 'comment', 'path', "length"];

    if (req.query.id) {
        exprs.push('id = ?');
        values.push(req.query.id);
    }
    else if (req.query.date) {
        exprs.push('date = ?');
        values.push(req.query.date);
    }
    else {
        if (req.query.year) {
            exprs.push('extract(year from DATE) = ?');
            values.push(parseInt(req.query.year));
        }
        if (req.query.month) {
            exprs.push('extract(month from DATE) = ?');
            values.push(parseInt(req.query.month));
        }

        if (req.query.filter == 'neighborhood') {
            var latitude  = parseFloat(req.query.latitude);
            var longitude = parseFloat(req.query.longitude);
            var radius    = parseFloat(req.query.radius);
            var dlat      = radius*180/Math.PI/models.EARTH_RADIUS;
            var mlat      = latitude > 0 ? latitude + dlat : latitude - dlat;
            var dlon      = dlat/Math.cos(mlat/180*Math.PI);
            var center    = Walk.getPoint(longitude, latitude);
            var lb        = Walk.getPoint(longitude-dlon, latitude-dlat);
            var rt        = Walk.getPoint(longitude+dlon, latitude+dlat);
            attributes.push([ util.format("st_distance(path, '%s', true)/1000", center), 'distance' ]);
            exprs.push('st_makebox2d(?, ?) && path', 'st_distance(path, ?, TRUE) <= ?');
            values.push(lb, rt,  center, radius);
        }
        else if (req.query.filter == 'cities') {
            var cities = req.query.cities.split(/,/).map(function (elm) { return "'" + elm + "'"; }).join(',');
            exprs.push("EXISTS (SELECT * FROM areas WHERE jcode IN (" + cities + ") AND path && the_geom AND ST_Intersects(path, the_geom))");
        }
        else if (req.query.filter == 'crossing') {
            var linestring = Walk.decodePath(req.query.searchPath);
            exprs.push("path && ?", "ST_Intersects(path, ?)");
            values.push(linestring, linestring);
        }
        else if (req.query.filter == 'hausdorff') {
            var max_distance = req.query.max_distance || 4000;
            linestring = Walk.decodePath(req.query.searchPath);
            extent     = Walk.getPathExtent(req.query.searchPath);
            dlat       = max_distance*180/Math.PI/models.EARTH_RADIUS;
            mlat       = Math.max(Math.abs(extent.ymax + dlat), Math.abs(extent.ymin-dlat));
            dlon       = dlat/Math.cos(mlat/180*Math.PI);
            lb         = Walk.getPoint(extent.xmin-dlon, extent.ymin-dlat);
            rt         = Walk.getPoint(extent.xmax+dlon, extent.ymax+dlat);

            attributes.push([util.format("ST_HausdorffDistance(ST_Transform(path, %d), ST_Transform('%s', %d))/1000", models.SRID_FOR_SIMILAR_SEARCH, linestring, models.SRID_FOR_SIMILAR_SEARCH), 'distance']);
            exprs.push('ST_Within(path, ST_SetSRID(ST_MakeBox2d(?, ?), ?))',
                'ST_HausdorffDistance(ST_Transform(path, ?), ST_Transform(?, ?)) < ?');
            values.push(lb, rt, models.SRID, models.SRID_FOR_SIMILAR_SEARCH, linestring, models.SRID_FOR_SIMILAR_SEARCH, max_distance);
        }
    }
    where = [exprs.map(function (e) { return '(' + e + ')';}).join(' AND ')].concat(values);
    var limit  = parseInt(req.query.limit) || 20;
    var offset = parseInt(req.query.offset) || 0;
    Walk.findAndCountAll({
        attributes : attributes,
        order  : order,
        where  : where,
        offset : offset,
        limit  : limit
    }).then(function ( result) {
        var params = null;
        if (result.count > offset + limit) {
            var q = Object.keys(req.query).filter(function (e) { return e != 'offset';}).map( function (e) { return e + '=' + req.query[e]; });
            q.push("offset=" +  (offset + limit));
            params = q.join('&');
        }
        res.json({
            count: result.count,
            params: params,
            rows:  result.rows.map(function (row) { return row.asObject(true); })
        });
    });
});

router.get('/add_city', function(req, res){
    var latitude  = parseFloat(req.query.latitude);
    var longitude = parseFloat(req.query.longitude);
    Area.find({
        where  : ['ST_Contains(the_geom, ST_SetSRID(ST_Point(?, ?), ?))', longitude, latitude, models.SRID],
    }).then(function (result) {
        res.json(result.asObject());
    });
});

router.post('/save', function(req, res) {
    var walk;
    var saveCallback = function (row) {
        res.json(row.asObject());
    };
    var linestring = req.body.path ? Walk.decodePath(req.body.path) : null;
    var query;
    var values;
    if (req.body.id) {
        if (linestring) {
            query = "UPDATE walks SET date = ?, title = ?, \"comment\" = ?, path = ?, length = ST_LENGTH(?, TRUE)/1000, updated_at = NOW() WHERE id = ? RETURNING *";
            values = [req.body.date, req.body.title, req.body.comment, linestring, linestring, req.body.id];
        }
        else {
            query = "UPDATE walks SET date = ?, title = ?, \"comment\" = ?, updated_at = NOW() WHERE id = ? RETURNING *";
            values = [req.body.date, req.body.title, req.body.comment, req.body.id];
        }
    }
    else {
        query = "INSERT INTO walks (date, title, \"comment\", path, length, created_at, updated_at) VALUES(?, ?, ?, ?, ST_LENGTH(?, TRUE)/1000, NOW(), NOW()) RETURNING *";
        values = [req.body.date, req.body.title, req.body.comment, linestring, linestring];
    }
    models.sequelize.query(query, {model: Walk, raw : true, replacements: values}).then(function (row) {
        res.json(row);
    });

});

router.get('/destroy/:id', function(req, res) {
    Walk.destroy({where : { id : req.params.id } }).then(function () {
        res.end('');
    });
});

router.get('/export/:id', function(req, res) {
    Walk.find({id : req.params.id }).then(function (row) {
        res.type('application/json');
        res.attachment(req.params.id + ".json");
        res.json(row.pathJSON());
    });
});
<|endoftext|>


<commit_before>'use strict';

var combineErrors = require('dbjs/lib/utils/combine-errors')
  , StringLine    = require('../string-line');

module.exports = StringLine.create('Enum', function (options) {
	if (options == null) return;
	if (Array.isArray(options)) {
		this._options.$setValue(options);
		return;
	}
	this._options.$setValue(null);
	Object.keys(options).forEach(function (name) {
		var option = this.$add(name), value = options[name];
		if (value === true) return;
		option.$setProperties(value);
	}, this._options);
}, {
	setOptions: function (options) {
		var error;
		if (options == null) throw new TypeError('Options cannot be null');
		error = this.validateConstruction(options);
		if (error) throw error;
		this.$construct(options);
	},
	validateConstruction: function (options) {
		var opts, error, errors;
		if (options == null) return null;
		if (Array.isArray(options)) {
			return this.StringLine.validateConstruction.call(this,
				{ options: options });
		}
		opts = [];
		Object.keys(Object(options)).forEach(function (name) {
			var error, value = options[name];
			opts.push(name);
			if (value === true) return;
			if (value == null) {
				error = new TypeError(value + " are not valid option properties");
			} else {
				error = this._itemPrototype_.validateProperties(value);
			}
			if (error) {
				if (!errors) errors = [];
				errors.push(error);
			}
		}, this.options);
		error = this.StringLine.validateConstruction.call(this,
			{ options: opts });
		if (errors) {
			error = combineErrors.apply(this, errors.concat(error));
			if (error) error.message = options + " is not valid options";
		}
		return error;
	},
	options: StringLine.rel({ multiple: true, required: true }),
	is: function (value) {
		if (typeof value !== 'string') return false;
		return this.options.has(value);
	},
	normalize: function (value) {
		return this.options.has(value) ? String(value) : null;
	}
}, {
	validateCreate: function (value) {
		if (!this.ns.options.has(value)) {
			return new TypeError(value + " is not a valid " + this._id_);
		}
		return null;
	}
});
<commit_msg>Enum.labels<commit_after>'use strict';

var combineErrors = require('dbjs/lib/utils/combine-errors')
  , StringLine    = require('../string-line');

module.exports = StringLine.create('Enum', function (options) {
	if (options == null) return;
	if (Array.isArray(options)) {
		this._options.$setValue(options);
		return;
	}
	this._options.$setValue(null);
	Object.keys(options).forEach(function (name) {
		var option = this.$add(name), value = options[name];
		if (value === true) return;
		option.$setProperties(value);
	}, this._options);
}, {
	setOptions: function (options) {
		var error;
		if (options == null) throw new TypeError('Options cannot be null');
		error = this.validateConstruction(options);
		if (error) throw error;
		this.$construct(options);
	},
	validateConstruction: function (options) {
		var opts, error, errors;
		if (options == null) return null;
		if (Array.isArray(options)) {
			return this.StringLine.validateConstruction.call(this,
				{ options: options });
		}
		opts = [];
		Object.keys(Object(options)).forEach(function (name) {
			var error, value = options[name];
			opts.push(name);
			if (value === true) return;
			if (value == null) {
				error = new TypeError(value + " are not valid option properties");
			} else {
				error = this._itemPrototype_.validateProperties(value);
			}
			if (error) {
				if (!errors) errors = [];
				errors.push(error);
			}
		}, this.options);
		error = this.StringLine.validateConstruction.call(this,
			{ options: opts });
		if (errors) {
			error = combineErrors.apply(this, errors.concat(error));
			if (error) error.message = options + " is not valid options";
		}
		return error;
	},
	options: StringLine.rel({ multiple: true, required: true }),
	labels: function () {
		var data = {};
		this._options.itemsListByOrder().forEach(function (item) {
			data[item._subject_] = item.label;
		});
		return data;
	},
	is: function (value) {
		if (typeof value !== 'string') return false;
		return this.options.has(value);
	},
	normalize: function (value) {
		return this.options.has(value) ? String(value) : null;
	}
}, {
	validateCreate: function (value) {
		if (!this.ns.options.has(value)) {
			return new TypeError(value + " is not a valid " + this._id_);
		}
		return null;
	}
});
<|endoftext|>


<commit_before>
// const RG = require('./battles');

/* eslint-disable max-len */
/*
 * Created by Pietro Polsinelli on 15/05/2015. Twitter: @ppolsinelli
 * Modified by Tuomas Poikela 2017,
 *  for roguelike Battles in the North
 *
 * First inspired by the simplicity of
 * http:// stackoverflow.com/questions/4241824/creating-an-ai-behavior-tree-in-c-sharp-how
 *
 */

function SelectorNode(conditionFunction, actionIfTrue, actionIfFalse) {
    this.conditionFunction = conditionFunction;
    this.actionIfTrue = actionIfTrue;
    this.actionIfFalse = actionIfFalse;
}

function SequencerNode(actionArray) {
    this.actionArray = actionArray;
}

function SelectorRandomNode(actionArray) {
    this.actionArray = actionArray;
}

function SequencerRandomNode(actionArray) {
    this.actionArray = actionArray;
}

//--------------------------------------------------------------------
// Utility functions
//--------------------------------------------------------------------

/*
 * From http:// stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
 */
function shuffle(array) {
    let currentIndex = array.length, temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

function execBehavTree(behaviourTreeNode, actor) {
    if (typeof actor.completedCurrentAction === 'undefined' || actor.completedCurrentAction === true) {

        if (Object.getPrototypeOf(behaviourTreeNode) === SelectorNode.prototype) {
            console.log('selector');
            selector(behaviourTreeNode, actor);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SequencerNode.prototype) {
            console.log('sequencer');
            sequencer(behaviourTreeNode, actor);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SequencerRandomNode.prototype) {
            sequencerRandom(behaviourTreeNode, actor);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SelectorRandomNode.prototype) {
            selectorRandom(behaviourTreeNode, actor);

        }
        else {
            const res = behaviourTreeNode(actor);
            return res;
        }
    }
    console.log('typeof actor.completedCurrentAction: ' + typeof actor.completedCurrentAction);
    console.log('actor.completedCurrentAction: ' + actor.completedCurrentAction);
    console.log('typeof node: ' + typeof behaviourTreeNode);
    console.log(JSON.stringify(behaviourTreeNode));
    console.log('execBehavTree Returning empty func now');
    return () => {};
}

// Private functions

function selector(selectorNode, actor) {
    if (execBehavTree(selectorNode.conditionFunction, actor)) {
        execBehavTree(selectorNode.actionIfTrue, actor);
    }
    else {
        execBehavTree(selectorNode.actionIfFalse, actor);
    }
}

function sequencer(sequencerNode, actor) {
    for (let i = 0; i < sequencerNode.actionArray.length; i++) {
        execBehavTree(sequencerNode.actionArray[i], actor);
    }
}

function sequencerRandom(sequencerRandomNode, actor) {
    shuffle(sequencerRandomNode.actionArray);
    for (let i = 0; i < sequencerRandomNode.actionArray.length; i++) {
        execBehavTree(sequencerRandomNode.actionArray[i], actor);
    }
}

function selectorRandom(selectorRandomNode, actor) {
    const randomIndex = Math.floor(Math.random() * selectorRandomNode.actionArray.length);
    execBehavTree(selectorRandomNode.actionArray[randomIndex], actor);
}

/*
function tick(behaviourTreeNode, actor) {
    setInterval(function() {
        execBehavTree(behaviourTreeNode, actor);
    }, 50);
}
*/

//----------------------------------------------------------------------
// EXAMPLES
//----------------------------------------------------------------------

const rogueModel = {};

rogueModel.ifPlayerIsInSight = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return playerCell !== null;
};

rogueModel.attackPlayer = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return brain.actionTowardsEnemy(playerCell);
};

/* Returns true if actor has 10% of health. */
rogueModel.ifSeriouslyWounded = function(actor) {
    const healthComp = actor.get('Health');
    const thr = Math.round(healthComp.getMaxHP() * 0.1);
    return healthComp.getHP() <= thr;
};

rogueModel.flee = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return brain.fleeFromCell(playerCell, seenCells);
};

rogueModel.exploreLevel = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    return brain.exploreLevel(seenCells);
};

const rogueModelBehavTree =
    new SelectorNode(
        rogueModel.ifSeriouslyWounded,
        new SequencerNode([rogueModel.flee]),
        new SelectorNode(
            rogueModel.ifPlayerIsInSight,
            rogueModel.attackPlayer,
            rogueModel.exploreLevel
        )
    );

/*
    const actor1 = new RG.Actor.Rogue('goblin');
    const player = new RG.Actor.Rogue('player');
    player.setIsPlayer(true);
    const level = RG.FACT.createLevel('arena', 10, 10);
    level.addActor(actor1, 1, 1);
    level.addActor(player, 3, 3);

    for (let i = 0; i < 10; i++) {
        execBehavTree(rogueModelBehavTree, actor1);
        if (i === 5) {
            actor1.get('Health').setHP(1);
        }
    }
*/
// }

// battlesExample();

const BTree = {
    SelectorNode,
    SequencerNode,
    SelectorRandomNode,
    SequencerRandomNode,
    execBehavTree,
    Model: {
        Rogue: rogueModelBehavTree
    }
};

module.exports = BTree;

<commit_msg>Added startBehavTree().<commit_after>
// const RG = require('./battles');

/* eslint-disable max-len */
/*
 * Created by Pietro Polsinelli on 15/05/2015. Twitter: @ppolsinelli
 * Modified by Tuomas Poikela 2017,
 *  for roguelike Battles in the North
 *
 * First inspired by the simplicity of
 * http:// stackoverflow.com/questions/4241824/creating-an-ai-behavior-tree-in-c-sharp-how
 *
 */

function SelectorNode(condFunc, actionIfTrue, actionIfFalse) {
    this.condFunc = condFunc;
    this.actionIfTrue = actionIfTrue;
    this.actionIfFalse = actionIfFalse;
}

function SequencerNode(actionArray) {
    this.actionArray = actionArray;
}

function SelectorRandomNode(actionArray) {
    this.actionArray = actionArray;
}

function SequencerRandomNode(actionArray) {
    this.actionArray = actionArray;
}

//--------------------------------------------------------------------
// Utility functions
//--------------------------------------------------------------------

/*
 * From http:// stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
 */
function shuffle(array) {
    let currentIndex = array.length, temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

function startBehavTree(behaviourTreeNode, actor) {
    const resArray = [];
    execBehavTree(behaviourTreeNode, actor, resArray);
    return resArray;
}

function execBehavTree(behaviourTreeNode, actor, resArray) {
    if (typeof actor.completedCurrentAction === 'undefined' || actor.completedCurrentAction === true) {

        if (Object.getPrototypeOf(behaviourTreeNode) === SelectorNode.prototype) {
            console.log('selector');
            selector(behaviourTreeNode, actor, resArray);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SequencerNode.prototype) {
            console.log('sequencer');
            sequencer(behaviourTreeNode, actor, resArray);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SequencerRandomNode.prototype) {
            sequencerRandom(behaviourTreeNode, actor, resArray);

        }
        else if (Object.getPrototypeOf(behaviourTreeNode) === SelectorRandomNode.prototype) {
            selectorRandom(behaviourTreeNode, actor, resArray);
        }
        else {
            const res = behaviourTreeNode(actor);
            if (typeof res === 'function') {
                resArray.push(res);
            }
            return res;
        }
    }
    console.log('typeof actor.completedCurrentAction: ' + typeof actor.completedCurrentAction);
    console.log('actor.completedCurrentAction: ' + actor.completedCurrentAction);
    console.log('typeof node: ' + typeof behaviourTreeNode);
    console.log(JSON.stringify(behaviourTreeNode));
    console.log('execBehavTree Returning empty func now');
    return () => {};
}

// Private functions

function selector(selectorNode, actor, arr) {
    if (execBehavTree(selectorNode.condFunc, actor, arr)) {
        execBehavTree(selectorNode.actionIfTrue, actor, arr);
    }
    else {
        execBehavTree(selectorNode.actionIfFalse, actor, arr);
    }
}

function sequencer(sequencerNode, actor, arr) {
    for (let i = 0; i < sequencerNode.actionArray.length; i++) {
        execBehavTree(sequencerNode.actionArray[i], actor, arr);
    }
}

function sequencerRandom(sequencerRandomNode, actor, arr) {
    shuffle(sequencerRandomNode.actionArray);
    for (let i = 0; i < sequencerRandomNode.actionArray.length; i++) {
        execBehavTree(sequencerRandomNode.actionArray[i], actor, arr);
    }
}

function selectorRandom(selectorRandomNode, actor, arr) {
    const randomIndex = Math.floor(Math.random() * selectorRandomNode.actionArray.length);
    execBehavTree(selectorRandomNode.actionArray[randomIndex], actor, arr);
}

/*
function tick(behaviourTreeNode, actor) {
    setInterval(function() {
        execBehavTree(behaviourTreeNode, actor);
    }, 50);
}
*/

//----------------------------------------------------------------------
// EXAMPLES
//----------------------------------------------------------------------

const rogueModel = {};

rogueModel.ifPlayerIsInSight = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return playerCell !== null;
};

rogueModel.attackPlayer = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return brain.actionTowardsEnemy(playerCell);
};

/* Returns true if actor has 10% of health. */
rogueModel.ifSeriouslyWounded = function(actor) {
    const healthComp = actor.get('Health');
    const thr = Math.round(healthComp.getMaxHP() * 0.1);
    return healthComp.getHP() <= thr;
};

rogueModel.flee = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    const playerCell = brain.findEnemyCell(seenCells);
    return brain.fleeFromCell(playerCell, seenCells);
};

rogueModel.exploreLevel = function(actor) {
    const brain = actor.getBrain();
    const seenCells = brain.getSeenCells();
    return brain.exploreLevel(seenCells);
};

const rogueModelBehavTree =
    new SelectorNode(
        rogueModel.ifSeriouslyWounded,
        new SequencerNode([rogueModel.flee]),
        new SelectorNode(
            rogueModel.ifPlayerIsInSight,
            rogueModel.attackPlayer,
            rogueModel.exploreLevel
        )
    );

/*
    const actor1 = new RG.Actor.Rogue('goblin');
    const player = new RG.Actor.Rogue('player');
    player.setIsPlayer(true);
    const level = RG.FACT.createLevel('arena', 10, 10);
    level.addActor(actor1, 1, 1);
    level.addActor(player, 3, 3);

    for (let i = 0; i < 10; i++) {
        execBehavTree(rogueModelBehavTree, actor1);
        if (i === 5) {
            actor1.get('Health').setHP(1);
        }
    }
*/
// }

// battlesExample();

const BTree = {
    SelectorNode,
    SequencerNode,
    SelectorRandomNode,
    SequencerRandomNode,
    execBehavTree,
    startBehavTree,
    Model: {
        Rogue: rogueModelBehavTree
    }
};

module.exports = BTree;

<|endoftext|>


<commit_before>"use strict"

/**
 * @type {Chai.Assert}
 */
var assert = require('chai').assert
var xdTesting = require('../../lib/index')
var templates = require('../../lib/templates')
var Flow = require('../../lib/flow/flow')
var q = require('q')

describe('xdTesting', function() {

    let test = this
    test.fixture = {
        xd_gallery: {
            url: 'http://localhost:8082/gallery.html'
        },
        basic_app: {
            url: 'http://localhost:8090/'
        }
    }

    // Reset config
    beforeEach(xdTesting.reset)
    afterEach(xdTesting.reset)

    describe('command arguments @large', function () {
        it('are part of a step\'s command name', function () {
            let scenario = {A: templates.devices.chrome()}
            return xdTesting.multiremote(scenario).init()
                .url(test.fixture.basic_app.url)
                .click('#button')
                .checkpoint('check')
                .getFlow().then(flow => {
                    let steps = flow.steps()
                    let stepCommandNames = steps.map(step => step.commands)
                        .filter(commands => commands.length > 0)
                    assert.lengthOf(stepCommandNames, 3)
                })
                .end()
        })
    })

    describe('#getFlow @large', function () {
        it('returns the flow object', function () {
            let scenario = {A: templates.devices.chrome()}
            return xdTesting.multiremote(scenario).init()
                .url(test.fixture.basic_app.url)
                .click('#button')
                .checkpoint('end')
                .getFlow().then(flow => {
                    assert.instanceOf(flow, Flow)
                    assert.property(flow, 'devices')
                    assert.deepPropertyVal(flow, 'devices.A.deviceId', 'A')
                })
                .end()

        })
    })

    describe('app framework integration', () => {

        it('should load xdTesting.baseUrl after init @large', () => {
            let options = {
                A: templates.devices.chrome()
            }

            xdTesting.baseUrl = 'http://localhost/'

            return xdTesting.multiremote(options).init()
                .getUrl().then(url => assert.equal(url, xdTesting.baseUrl))
                .end()
        })

        it('should not load xdTesting.baseUrl if it\'s not set @large', () => {
            let options = {
                A: templates.devices.chrome()
            }

            xdTesting.baseUrl = null

            return xdTesting.multiremote(options).init()
                .getUrl().then(url => assert.equal(url, 'data:,'))
                .end()
        })

        describe('for XD-MVC', () => {

            // Define a custom adapter
            beforeEach(() => {
                xdTesting.appFramework = xdTesting.adapter.xdmvc
            })

            it('app property has devices @medium', () => {
                let options = {
                    A: templates.devices.chrome()
                }

                let devices = xdTesting.multiremote(options)
                let app = devices
                    .app()

                assert.property(app, 'devices')
                assert.isDefined(app.devices)

                return devices.end()
            })

            it('app property should have getEventCounter @medium', () => {
                let options = {
                    A: templates.devices.chrome()
                }

                let devices = xdTesting.multiremote(options)
                let app = devices
                    .app()

                assert.property(app, 'getEventCounter')
                assert.instanceOf(app.getEventCounter, Function)

                return devices.end()
            })

            it('should get the event counter @large', () => {
                let options = {
                    A: templates.devices.chrome()
                }
                return xdTesting.multiremote(options).init()
                    .url(test.fixture.xd_gallery.url)
                    .app().injectEventLogger()
                    .app().getEventCounter().then(counter => {
                        assert.property(counter, 'XDdisconnection')
                        assert.property(counter, 'XDconnection')
                        assert.property(counter, 'XDdevice')
                        assert.property(counter, 'XDroles')
                        assert.property(counter, 'XDsync')
                        assert.property(counter, 'XDserverReady')
                        assert.property(counter, 'XDothersRolesChanged')

                        assert.typeOf(counter['XDdisconnection'], 'number')
                        assert.typeOf(counter['XDconnection'], 'number')
                        assert.typeOf(counter['XDdevice'], 'number')
                        assert.typeOf(counter['XDroles'], 'number')
                        assert.typeOf(counter['XDsync'], 'number')
                        assert.typeOf(counter['XDserverReady'], 'number')
                        assert.typeOf(counter['XDothersRolesChanged'], 'number')
                    })
                    .end()

                    /**
                     * App property?
                     */

                    //// Pair devices via url
                    //.app.pairDevicesViaUrl()
                    // Get event counter
                    //.app.getEventCounter().then(counter => assert.equal(counter.XDconnection == 1))
                // Wait for the next event of a type
                //.app.waitForEvent('XDconnection')
                //// Wait until the event type counter equals a value
                //.app.waitForEventCount('XDconnection', 2)
                //// Custom command
                //.app.addCommand('pairDevicesViaGUI', function() {
                //    return this.click(...)
                //})
            })

            describe('pairDevicesViaUrl', () => {
                it('should pair a device with a other device', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }
                    let urlA
                    return xdTesting.multiremote(options).init()
                        .app().pairDevicesViaURL(test.fixture.xd_gallery.url)
                        .getUrl().then((urlA, urlB) => {
                            assert.include(urlA, test.fixture.xd_gallery.url)
                            assert.strictEqual(urlA, urlB)
                        })
                        .end()
                })
            })

            describe('pairDevicesViaXDMVC', () => {
                it('should pair a device with a other device', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }
                    let urlA
                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().pairDevicesViaXDMVC()
                        .app().getEventCounter().then((counterA, counterB) => {
                            assert.equal(counterA['XDconnection'], 1)
                            assert.equal(counterB['XDconnection'], 1)
                        })
                        .end()
                })
            })

            describe('waitForConnectedDevices', () => {
                it('for 0 connected devices should return immediately', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().waitForConnectedDevices(0)
                        .end()
                })

                it('for 1 connected devices should return after connection', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }

                    let queue = ''
                    let devices = xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .then(() => queue += '0')

                    let waitFor = devices
                        .then(() => queue += '1')
                        .app().waitForConnectedDevices(1)

                    let trigger = devices
                        .then(() => q.delay(1000))
                        .then(() => queue += '2')
                        .app().pairDevicesViaXDMVC()
                        .then(() => queue += '3')

                    return waitFor
                        .then(() => assert.equal(queue, '0123'))
                        .end()
                })
            })

            describe('waitForEvent', () => {
                it('should wait for the next event of the given type', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    let queue = ''
                    let lastCounter
                    let devices = xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().injectEventLogger()
                        .app().getEventCounter()
                        .then(counter => lastCounter = counter)
                        .then(() => queue += '0')
                        // Init a custom event counter
                        .execute(function() {
                            window.eventLogger.eventCounter['customEvent'] = 0
                        })
                        .then(() => queue += '1')

                    let waitFor = devices
                        .then(() => queue += '2')
                        .app().waitForEvent('customEvent')
                        .then(() => queue += '9')
                        .end()

                    let trigger = devices
                        .then(() => q.delay(1000))
                        .then(() => queue += '3')
                        .execute(function() {
                            window.eventLogger.eventCounter['customEvent'] = 1
                        })
                        .then(() => queue += '4')

                    return waitFor
                        .then(() => assert.equal(queue, '012349'))
                        .end()
                })
            })

            describe('hooks', () => {
                it('should inject event logger after loading url', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    xdTesting.reset()
                    xdTesting.appFramework = xdTesting.adapter.xdmvc

                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .execute(function() {
                            return window.eventLogger;
                        })
                        .then(ret => assert.isDefined(ret))
                        .app().getEventCounter().then(counter => {
                            assert.isDefined(counter)
                        })
                        .end()
                })
            })
        })

    })
})
<commit_msg>Document test sizes<commit_after>"use strict"

/**
 * @type {Chai.Assert}
 */
var assert = require('chai').assert
var xdTesting = require('../../lib/index')
var templates = require('../../lib/templates')
var Flow = require('../../lib/flow/flow')
var q = require('q')

describe('xdTesting', function() {

    let test = this
    test.fixture = {
        xd_gallery: {
            url: 'http://localhost:8082/gallery.html'
        },
        basic_app: {
            url: 'http://localhost:8090/'
        }
    }

    // Reset config
    beforeEach(xdTesting.reset)
    afterEach(xdTesting.reset)

    describe('command arguments @large', function () {
        it('are part of a step\'s command name', function () {
            let scenario = {A: templates.devices.chrome()}
            return xdTesting.multiremote(scenario).init()
                .url(test.fixture.basic_app.url)
                .click('#button')
                .checkpoint('check')
                .getFlow().then(flow => {
                    let steps = flow.steps()
                    let stepCommandNames = steps.map(step => step.commands)
                        .filter(commands => commands.length > 0)
                    assert.lengthOf(stepCommandNames, 3)
                })
                .end()
        })
    })

    describe('#getFlow @large', function () {
        it('returns the flow object', function () {
            let scenario = {A: templates.devices.chrome()}
            return xdTesting.multiremote(scenario).init()
                .url(test.fixture.basic_app.url)
                .click('#button')
                .checkpoint('end')
                .getFlow().then(flow => {
                    assert.instanceOf(flow, Flow)
                    assert.property(flow, 'devices')
                    assert.deepPropertyVal(flow, 'devices.A.deviceId', 'A')
                })
                .end()

        })
    })

    describe('app framework integration', () => {

        it('should load xdTesting.baseUrl after init @large', () => {
            let options = {
                A: templates.devices.chrome()
            }

            xdTesting.baseUrl = 'http://localhost/'

            return xdTesting.multiremote(options).init()
                .getUrl().then(url => assert.equal(url, xdTesting.baseUrl))
                .end()
        })

        it('should not load xdTesting.baseUrl if it\'s not set @large', () => {
            let options = {
                A: templates.devices.chrome()
            }

            xdTesting.baseUrl = null

            return xdTesting.multiremote(options).init()
                .getUrl().then(url => assert.equal(url, 'data:,'))
                .end()
        })

        describe('for XD-MVC', () => {

            // Define a custom adapter
            beforeEach(() => {
                xdTesting.appFramework = xdTesting.adapter.xdmvc
            })

            it('app property has devices @medium', () => {
                let options = {
                    A: templates.devices.chrome()
                }

                let devices = xdTesting.multiremote(options)
                let app = devices
                    .app()

                assert.property(app, 'devices')
                assert.isDefined(app.devices)

                return devices.end()
            })

            it('app property should have getEventCounter @medium', () => {
                let options = {
                    A: templates.devices.chrome()
                }

                let devices = xdTesting.multiremote(options)
                let app = devices
                    .app()

                assert.property(app, 'getEventCounter')
                assert.instanceOf(app.getEventCounter, Function)

                return devices.end()
            })

            it('should get the event counter @large', () => {
                let options = {
                    A: templates.devices.chrome()
                }
                return xdTesting.multiremote(options).init()
                    .url(test.fixture.xd_gallery.url)
                    .app().injectEventLogger()
                    .app().getEventCounter().then(counter => {
                        assert.property(counter, 'XDdisconnection')
                        assert.property(counter, 'XDconnection')
                        assert.property(counter, 'XDdevice')
                        assert.property(counter, 'XDroles')
                        assert.property(counter, 'XDsync')
                        assert.property(counter, 'XDserverReady')
                        assert.property(counter, 'XDothersRolesChanged')

                        assert.typeOf(counter['XDdisconnection'], 'number')
                        assert.typeOf(counter['XDconnection'], 'number')
                        assert.typeOf(counter['XDdevice'], 'number')
                        assert.typeOf(counter['XDroles'], 'number')
                        assert.typeOf(counter['XDsync'], 'number')
                        assert.typeOf(counter['XDserverReady'], 'number')
                        assert.typeOf(counter['XDothersRolesChanged'], 'number')
                    })
                    .end()

                    /**
                     * App property?
                     */

                    //// Pair devices via url
                    //.app.pairDevicesViaUrl()
                    // Get event counter
                    //.app.getEventCounter().then(counter => assert.equal(counter.XDconnection == 1))
                // Wait for the next event of a type
                //.app.waitForEvent('XDconnection')
                //// Wait until the event type counter equals a value
                //.app.waitForEventCount('XDconnection', 2)
                //// Custom command
                //.app.addCommand('pairDevicesViaGUI', function() {
                //    return this.click(...)
                //})
            })

            describe('pairDevicesViaUrl @large', () => {
                it('should pair a device with a other device', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }
                    let urlA
                    return xdTesting.multiremote(options).init()
                        .app().pairDevicesViaURL(test.fixture.xd_gallery.url)
                        .getUrl().then((urlA, urlB) => {
                            assert.include(urlA, test.fixture.xd_gallery.url)
                            assert.strictEqual(urlA, urlB)
                        })
                        .end()
                })
            })

            describe('pairDevicesViaXDMVC @large', () => {
                it('should pair a device with a other device', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }
                    let urlA
                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().pairDevicesViaXDMVC()
                        .app().getEventCounter().then((counterA, counterB) => {
                            assert.equal(counterA['XDconnection'], 1)
                            assert.equal(counterB['XDconnection'], 1)
                        })
                        .end()
                })
            })

            describe('waitForConnectedDevices @large', () => {
                it('for 0 connected devices should return immediately', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().waitForConnectedDevices(0)
                        .end()
                })

                it('for 1 connected devices should return after connection', () => {
                    let options = {
                        A: templates.devices.chrome(),
                        B: templates.devices.chrome()
                    }

                    let queue = ''
                    let devices = xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .then(() => queue += '0')

                    let waitFor = devices
                        .then(() => queue += '1')
                        .app().waitForConnectedDevices(1)

                    let trigger = devices
                        .then(() => q.delay(1000))
                        .then(() => queue += '2')
                        .app().pairDevicesViaXDMVC()
                        .then(() => queue += '3')

                    return waitFor
                        .then(() => assert.equal(queue, '0123'))
                        .end()
                })
            })

            describe('waitForEvent @large', () => {
                it('should wait for the next event of the given type', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    let queue = ''
                    let lastCounter
                    let devices = xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .app().injectEventLogger()
                        .app().getEventCounter()
                        .then(counter => lastCounter = counter)
                        .then(() => queue += '0')
                        // Init a custom event counter
                        .execute(function() {
                            window.eventLogger.eventCounter['customEvent'] = 0
                        })
                        .then(() => queue += '1')

                    let waitFor = devices
                        .then(() => queue += '2')
                        .app().waitForEvent('customEvent')
                        .then(() => queue += '9')
                        .end()

                    let trigger = devices
                        .then(() => q.delay(1000))
                        .then(() => queue += '3')
                        .execute(function() {
                            window.eventLogger.eventCounter['customEvent'] = 1
                        })
                        .then(() => queue += '4')

                    return waitFor
                        .then(() => assert.equal(queue, '012349'))
                        .end()
                })
            })

            describe('hooks', () => {
                it('should inject event logger after loading url', () => {
                    let options = {
                        A: templates.devices.chrome()
                    }

                    xdTesting.reset()
                    xdTesting.appFramework = xdTesting.adapter.xdmvc

                    return xdTesting.multiremote(options).init()
                        .url(test.fixture.xd_gallery.url)
                        .execute(function() {
                            return window.eventLogger;
                        })
                        .then(ret => assert.isDefined(ret))
                        .app().getEventCounter().then(counter => {
                            assert.isDefined(counter)
                        })
                        .end()
                })
            })
        })

    })
})
<|endoftext|>


<commit_before>var gulp = require("gulp");
var browser = require("browser-sync");
var plumber = require("gulp-plumber");

gulp.task("server", function() {
    browser({
        proxy: "vccw.dev"
    });
});

gulp.task('php-reload', function () {
    gulp.src("src/**/*.php")
    .pipe(cache( 'php-reload' ))
    .pipe(browser.reload({stream:true}))
    .pipe(notify({
        title: 'HTMLの変更、ブラウザリロード。',
        message: new Date(),
        sound: 'Submarine',
        icon: 'logo.png'
    }));
});

gulp.task('watch', function () {
    gulp.watch("www/**/*.php",["php-reload"]);
});

gulp.task("default", ['server' , 'watch'] );
<commit_msg>phpのライブリロード機能を追加<commit_after>var gulp = require("gulp");
var browser = require("browser-sync");
var plumber = require("gulp-plumber");

gulp.task("server", function() {
    browser({
        proxy: "vccw.dev"
    });
});

gulp.task('php-reload', function () {
    gulp.src("www/**/*.php")
    .pipe(browser.reload({stream:true}))
});

gulp.task('watch', function () {
    gulp.watch("www/**/*.php",["php-reload"]);
});

gulp.task("default", ['server' , 'watch'] );
<|endoftext|>