<commit_before>'use strict';

module.exports =
angular.module('quill-grammar.services.crud', [
  'firebase',
  'underscore',
])

.factory('CrudService', function(firebaseUrl, $firebase, $q, _) {
  function crud(entity, properties, prefix) {
    if (!entity || entity === '') {
      throw new Error('Firebase Entity MUST be defined');
    }
    if (!properties) {
      throw new Error('Please define the properties for your entity ' + entity);
    }
    if (firebaseUrl[firebaseUrl.length - 1] !== '/') {
      firebaseUrl = firebaseUrl + '/';
    }
    var baseUrl = String(firebaseUrl);
    if (prefix) {
      baseUrl = baseUrl + prefix + '/';
    }
    var baseRoute = baseUrl + entity;
    var baseRef = $firebase(new Firebase(baseRoute));
    var baseCollection = baseRef.$asObject();

    function getRef() {
      return baseRef;
    }

    function sanitize(item) {
      if (properties && _.isObject(item)) {
        return _.pick(item, function(value, key) {
          return key[0] === '$' || _.contains(properties, key);
        });
      }
      return item;
    }

    function isValid(item) {
      return !(_.has(item, '$value')) || !_.isUndefined(item.$value);
    }

    function save(item) {
      var d = $q.defer();
      var entityItem = sanitize(item);
      baseRef.$push(entityItem).then(function(ref) {
        d.resolve(ref.key());
      }, function(error){
        d.reject(error);
      });
      return d.promise;
    }

    function del(item) {
      var d = $q.defer();
      if (!item || !item.$id) {
        throw new Error('Item doesn\'t have an $id property');
      }
      baseRef.$remove(item.$id).then(function(ref) {
        d.resolve(ref.key());
      }, function(error) {
        d.reject(error);
      });

      return d.promise;
    }

    function all() {
      var d = $q.defer();
      var a = baseRef.$asArray();
      a.$loaded().then(function() {
        d.resolve(a);
      }, function(error) {
        d.reject(error);
      });
      return d.promise;
    }

    function get(entityId) {
      var d = $q.defer();
      var entityRef = new Firebase(baseRoute + '/' + entityId);
      var entity = $firebase(entityRef).$asObject();
      entity.$loaded().then(function(entityData) {
        if (isValid(entityData)) {
          d.resolve(entityData);
        } else {
          console.error(entityId);
          console.error(entityData);
          d.reject(new Error('Entity did not meet the properties requirement'));
        }
      }, function(error) {
        d.reject(error);
      });
      return d.promise;
    }

    function update(item) {
      var d = $q.defer();
      baseCollection.$loaded().then(function() {
        var index = item.$id;
        baseCollection[index] = sanitize(item);
        baseCollection.$save(index).then(function(ref) {
          console.log(ref.key());
          d.resolve(ref.key());
        }, function(error){
          console.log(error);
          d.reject(error);
        });
      });
      return d.promise;
    }

    return {
      save: save,
      del: del,
      all: all,
      get: get,
      update: update,
      getRef: getRef,
    };
  }

  return crud;
});
<commit_msg>Check for null in crud<commit_after>'use strict';

module.exports =
angular.module('quill-grammar.services.crud', [
  'firebase',
  'underscore',
])

.factory('CrudService', function(firebaseUrl, $firebase, $q, _) {
  function crud(entity, properties, prefix) {
    if (!entity || entity === '') {
      throw new Error('Firebase Entity MUST be defined');
    }
    if (!properties) {
      throw new Error('Please define the properties for your entity ' + entity);
    }
    if (firebaseUrl[firebaseUrl.length - 1] !== '/') {
      firebaseUrl = firebaseUrl + '/';
    }
    var baseUrl = String(firebaseUrl);
    if (prefix) {
      baseUrl = baseUrl + prefix + '/';
    }
    var baseRoute = baseUrl + entity;
    var baseRef = $firebase(new Firebase(baseRoute));
    var baseCollection = baseRef.$asObject();

    function getRef() {
      return baseRef;
    }

    function sanitize(item) {
      if (properties && _.isObject(item)) {
        return _.pick(item, function(value, key) {
          return key[0] === '$' || _.contains(properties, key);
        });
      }
      return item;
    }

    function isValid(item) {
      return !(_.has(item, '$value')) || (!_.isUndefined(item.$value) && !_.isNull(item.$value));
    }

    function save(item) {
      var d = $q.defer();
      var entityItem = sanitize(item);
      baseRef.$push(entityItem).then(function(ref) {
        d.resolve(ref.key());
      }, function(error){
        d.reject(error);
      });
      return d.promise;
    }

    function del(item) {
      var d = $q.defer();
      if (!item || !item.$id) {
        throw new Error('Item doesn\'t have an $id property');
      }
      baseRef.$remove(item.$id).then(function(ref) {
        d.resolve(ref.key());
      }, function(error) {
        d.reject(error);
      });

      return d.promise;
    }

    function all() {
      var d = $q.defer();
      var a = baseRef.$asArray();
      a.$loaded().then(function() {
        d.resolve(a);
      }, function(error) {
        d.reject(error);
      });
      return d.promise;
    }

    function get(entityId) {
      var d = $q.defer();
      var entityRef = new Firebase(baseRoute + '/' + entityId);
      var entity = $firebase(entityRef).$asObject();
      entity.$loaded().then(function(entityData) {
        if (isValid(entityData)) {
          d.resolve(entityData);
        } else {
          console.error(entityId);
          console.error(entityData);
          d.reject(new Error('Entity did not meet the properties requirement'));
        }
      }, function(error) {
        d.reject(error);
      });
      return d.promise;
    }

    function update(item) {
      var d = $q.defer();
      baseCollection.$loaded().then(function() {
        var index = item.$id;
        baseCollection[index] = sanitize(item);
        baseCollection.$save(index).then(function(ref) {
          console.log(ref.key());
          d.resolve(ref.key());
        }, function(error){
          console.log(error);
          d.reject(error);
        });
      });
      return d.promise;
    }

    return {
      save: save,
      del: del,
      all: all,
      get: get,
      update: update,
      getRef: getRef,
    };
  }

  return crud;
});
<|endoftext|>


<commit_before>/**
 * Created by truthlighting on 9/14/2016.
 */
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
if (!Memory.hCreepID) {
    Memory.hCreepID = 1;
}
if (!Memory.bCreepID) {
    Memory.bCreepID = 1;
}
if (!Memory.uCreepID) {
    Memory.uCreepID = 1;
}

module.exports.loop = function () {

    for(var name in Memory.creeps) {
        if(!Game.creeps[name]) {
            delete Memory.creeps[name];
            console.log('Clearing non-existing creep memory:', name);
        }
    }

    var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
//    console.log('Harvesters: ' + harvesters.length);

    if(harvesters.length < 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "H-" + Memory.hCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "H-" + Memory.hCreepID, {role: 'harvester'});
        Memory.hCreepID++;
        console.log('Spawning new harvester: ' + newName);
    }

    var upgraders = _.filter(Game.creeps, (creep) => creep.memory.role == 'upgrader');
//    console.log('Upgraders: ' + harvesters.length);

    if(upgraders.length < 3 && harvesters.length >= 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "U-" + Memory.uCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "U-" + Memory.uCreepID, {role: 'upgrader'});
        Memory.uCreepID++;
        console.log('Spawning new upgrader: ' + newName);
    }

    var builders = _.filter(Game.creeps, (creep) => creep.memory.role == 'builder');
//    console.log('Upgraders: ' + harvesters.length);

    if(builders.length < 3 && harvesters.length >= 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "B-" + Memory.bCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE], "B-" + Memory.bCreepID, {role: 'builder'});
        Memory.bCreepID++;
        console.log('Spawning new builder: ' + newName);
    }

    for(var name in Game.creeps) {
        var creep = Game.creeps[name];
        if(creep.memory.role == 'harvester') {
            roleHarvester.run(creep);
        }
        if(creep.memory.role == 'upgrader') {
            roleUpgrader.run(creep);
        }
        if(creep.memory.role == 'builder') {
            roleBuilder.run(creep);
        }
    }

};<commit_msg>Increase size of creeps<commit_after>/**
 * Created by truthlighting on 9/14/2016.
 */
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
if (!Memory.hCreepID) {
    Memory.hCreepID = 1;
}
if (!Memory.bCreepID) {
    Memory.bCreepID = 1;
}
if (!Memory.uCreepID) {
    Memory.uCreepID = 1;
}

module.exports.loop = function () {

    for(var name in Memory.creeps) {
        if(!Game.creeps[name]) {
            delete Memory.creeps[name];
            console.log('Clearing non-existing creep memory:', name);
        }
    }

    var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
//    console.log('Harvesters: ' + harvesters.length);

    if(harvesters.length < 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "H-" + Memory.hCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "H-" + Memory.hCreepID, {role: 'harvester'});
        Memory.hCreepID++;
        console.log('Spawning new harvester: ' + newName);
    }

    var upgraders = _.filter(Game.creeps, (creep) => creep.memory.role == 'upgrader');
//    console.log('Upgraders: ' + harvesters.length);

    if(upgraders.length < 3 && harvesters.length >= 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "U-" + Memory.uCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "U-" + Memory.uCreepID, {role: 'upgrader'});
        Memory.uCreepID++;
        console.log('Spawning new upgrader: ' + newName);
    }

    var builders = _.filter(Game.creeps, (creep) => creep.memory.role == 'builder');
//    console.log('Upgraders: ' + harvesters.length);

    if(builders.length < 3 && harvesters.length >= 3 && Game.spawns['Harmony'].canCreateCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "B-" + Memory.bCreepID)==OK) {
        var newName = Game.spawns['Harmony'].createCreep([WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE], "B-" + Memory.bCreepID, {role: 'builder'});
        Memory.bCreepID++;
        console.log('Spawning new builder: ' + newName);
    }

    for(var name in Game.creeps) {
        var creep = Game.creeps[name];
        if(creep.memory.role == 'harvester') {
            roleHarvester.run(creep);
        }
        if(creep.memory.role == 'upgrader') {
            roleUpgrader.run(creep);
        }
        if(creep.memory.role == 'builder') {
            roleBuilder.run(creep);
        }
    }

};<|endoftext|>


<commit_before>// Create the module and name it app
var app = angular.module('DockerWebUI', ['ngCookies','ngRoute']);

/*
 *This config command configures all $http requests to be send with 'X-Requested-With' header
 * which is required by docker-registry flask server
 */
app.config(function($httpProvider){
	delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// configure our routes.
/*
 *Using routes we create a single page application(SPA), with index.html as the base template and then loading
 *various views using ng-view, and anchor tags.
 */
app.config(function($routeProvider) {
	$routeProvider

		// route for the home page
		.when('/', {
			templateUrl : 'pages/home.html',
			controller  : 'MainController'
		})

		// route for the showNamespaces page
		.when('/showNamespaces', {
			templateUrl : 'pages/showNamespaces.html',
			controller  : 'NamespacesController'
		})

		// route for the showRepositories page
		.when('/showRepositories', {
			templateUrl : 'pages/showRepositories.html',
			controller  : 'RepositoriesController'
		})

		// route for the showImages page
		.when('/showImages', {
			templateUrl : 'pages/showImages.html',
			controller  : 'ImagesController'
		});
});

/*This service is used to define the object which stores the current Docker-registry IP address and defines the getter and setter
  methods for accessing  and modifyingthe IP address.
*/
app.service('IPService', function () {
	var IP = '192.168.1.1';
	return {
		getIP: function () {
			return IP;
		},
		setIP: function(value) {
			IP = value;
		}
	};
});

// create the Main controller (for index.html) and inject Angular's $scope
app.controller('MainController', ['$scope','IPService','$route','$window','$cookies',function($scope,IPService,$route,$window,$cookies) {
	// create a message to display in our view
	$scope.inputIP='';
	//$cookies.IP='localhost';
	//$scope.cookieIP=$cookies.IP;
	//console.log('The cookiestore ip is' + $scope.cookieIP);
	$scope.setIP=function(inputIP,$cookieStore)
	{
		IPService.setIP(inputIP);
		$cookies.IP=inputIP;
		//$cookieStore.put(‘IP’, inputIP);
		console.log('the IP has been changed to '+IPService.getIP());
		$window.location.href = "#showNamespaces";
	}
}]);

//Show Namespaces controller, all JS code for showNamespaces page is here
app.controller('NamespacesController', function($rootScope,$scope,$http,IPService,$route,$cookies) {

	$scope.message = 'shownamespaces page';
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.IP=$cookieStore.get(‘ip’);
	console.log('the ip is ' + $scope.IP);
	$scope.num_results=0;
	$scope.dictionary={};
	$scope.namespacesList=[];
	results=[];
	//namespaces=[];
	//images=[];

	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			$scope.dictionary[result.name.split('/')[0]]=[];
		});
		angular.forEach(results,function(result)
		{
			//namespaces.push(result.name.split('/')[0]);
			//images.push(result.name.split('/')[1]);
			$scope.dictionary[result.name.split('/')[0]].push(result.name.split('/')[1]);
		});
		angular.forEach($scope.dictionary,function(key,value)
		{
			temp={};
			temp['name']=value;
			$scope.namespacesList.push(temp);
		});
	}).error(function(data){alert('Unable to reuest.')});

});

//Show repositories controller, all JS code for showRepositories page is here
app.controller('RepositoriesController', function($scope,$http,$location,IPService,$window,$cookies) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	$scope.namespace=$location.search()['namespace'];
	$scope.num_results=0;
	$scope.repositoriesList=[];
	$scope.go = function (path) {
	$location.path(path);
	};
	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			if(result.name.split('/')[0]===$scope.namespace)
			{
				temp={};
				temp['name']=result.name.split('/')[1];
				$scope.repositoriesList.push(temp);
			}
		});
	}).error(function(data){alert('Unable to request.')});
});

//Show images controller, all JS code for showImages page is here
app.controller('ImagesController', function($scope,$http,$location,IPService,$window,$cookies) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.newTag='';
	$scope.namespace=$location.search()['namespace'];
	$scope.repository=$location.search()['repository'];
	$scope.tagsList=[];
	URL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+$scope.repository+'/tags';
	$scope.deleteTag = function (tag)
	{

			$http.delete(URL+'/'+tag).success(function (data)
			{
				console.log('Deleted tag : '+tag);
				$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
			}).error(function(data){alert('Unable to delete.')});;
	};

	/*This function gets 2 parameters the old tag before editand the new tag after edit.
	 * This function will delete the old tag after getting the image id attached to it, use this image ID
	 * to put the new tag in the repository, thus having the same effect as editing a tag.
	 */
	$scope.changeTag = function (oldTag,newTag)
	{
		$scope.oldTagURL=URL+'/'+oldTag;
		$scope.newTagURL=URL+'/'+newTag;
		$scope.imageID='';
		imageId='\"hello\"';
		console.log('image id fetch url is '+ $scope.oldTagURL);
		console.log('tag putting url is ' + $scope.newTagURL);
		console.log('new tag is '+ newTag);
		$http({method: 'GET', url: $scope.oldTagURL }).success(function(data)
		{
			console.log('Data fetched : '+data);
			imageId='\"'+data.replace(/"/g,'')+'\"';

			$http({method: 'PUT', url: $scope.newTagURL, data: imageId , headers: {"Content-Type": "application/json","Accept": "application/json"}}).success(function(data)
			{
				$http.delete($scope.oldTagURL).success(function (data)
				{

					$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
				}).error(function(data){alert('Unable to delete.')});

			}).error(function(data){
				console.log('Unable to set tag for imageID');

				});

		}).error(function(data){console.log('Unable to get image ID for tag')});

	}

	$http({method: 'GET', url: URL }).success(function(data)
	{
		$scope.results=data;
		numTags=0;
		angular.forEach($scope.results,function(key,value)
		{
			numTags++;
			temp={};
			temp['name']=value;
			temp['id']=numTags;
			$scope.tagsList.push(temp);
		});
	}).error(function(data){alert('Unable to request.')});
});

<commit_msg>Edit Tags Feature : small bug fix for same oldTag and newTag while edit<commit_after>// Create the module and name it app
var app = angular.module('DockerWebUI', ['ngCookies','ngRoute']);

/*
 *This config command configures all $http requests to be send with 'X-Requested-With' header
 * which is required by docker-registry flask server
 */
app.config(function($httpProvider){
	delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// configure our routes.
/*
 *Using routes we create a single page application(SPA), with index.html as the base template and then loading
 *various views using ng-view, and anchor tags.
 */
app.config(function($routeProvider) {
	$routeProvider

		// route for the home page
		.when('/', {
			templateUrl : 'pages/home.html',
			controller  : 'MainController'
		})

		// route for the showNamespaces page
		.when('/showNamespaces', {
			templateUrl : 'pages/showNamespaces.html',
			controller  : 'NamespacesController'
		})

		// route for the showRepositories page
		.when('/showRepositories', {
			templateUrl : 'pages/showRepositories.html',
			controller  : 'RepositoriesController'
		})

		// route for the showImages page
		.when('/showImages', {
			templateUrl : 'pages/showImages.html',
			controller  : 'ImagesController'
		});
});

/*This service is used to define the object which stores the current Docker-registry IP address and defines the getter and setter
  methods for accessing  and modifyingthe IP address.
*/
app.service('IPService', function () {
	var IP = '192.168.1.1';
	return {
		getIP: function () {
			return IP;
		},
		setIP: function(value) {
			IP = value;
		}
	};
});

// create the Main controller (for index.html) and inject Angular's $scope
app.controller('MainController', ['$scope','IPService','$route','$window','$cookies',function($scope,IPService,$route,$window,$cookies) {
	// create a message to display in our view
	$scope.inputIP='';
	//$cookies.IP='localhost';
	//$scope.cookieIP=$cookies.IP;
	//console.log('The cookiestore ip is' + $scope.cookieIP);
	$scope.setIP=function(inputIP,$cookieStore)
	{
		IPService.setIP(inputIP);
		$cookies.IP=inputIP;
		//$cookieStore.put(‘IP’, inputIP);
		console.log('the IP has been changed to '+IPService.getIP());
		$window.location.href = "#showNamespaces";
	}
}]);

//Show Namespaces controller, all JS code for showNamespaces page is here
app.controller('NamespacesController', function($rootScope,$scope,$http,IPService,$route,$cookies) {

	$scope.message = 'shownamespaces page';
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.IP=$cookieStore.get(‘ip’);
	console.log('the ip is ' + $scope.IP);
	$scope.num_results=0;
	$scope.dictionary={};
	$scope.namespacesList=[];
	results=[];
	//namespaces=[];
	//images=[];

	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			$scope.dictionary[result.name.split('/')[0]]=[];
		});
		angular.forEach(results,function(result)
		{
			//namespaces.push(result.name.split('/')[0]);
			//images.push(result.name.split('/')[1]);
			$scope.dictionary[result.name.split('/')[0]].push(result.name.split('/')[1]);
		});
		angular.forEach($scope.dictionary,function(key,value)
		{
			temp={};
			temp['name']=value;
			$scope.namespacesList.push(temp);
		});
	}).error(function(data){alert('Unable to reuest.')});

});

//Show repositories controller, all JS code for showRepositories page is here
app.controller('RepositoriesController', function($scope,$http,$location,IPService,$window,$cookies) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	$scope.namespace=$location.search()['namespace'];
	$scope.num_results=0;
	$scope.repositoriesList=[];
	$scope.go = function (path) {
	$location.path(path);
	};
	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			if(result.name.split('/')[0]===$scope.namespace)
			{
				temp={};
				temp['name']=result.name.split('/')[1];
				$scope.repositoriesList.push(temp);
			}
		});
	}).error(function(data){alert('Unable to request.')});
});

//Show images controller, all JS code for showImages page is here
app.controller('ImagesController', function($scope,$http,$location,IPService,$window,$cookies) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.newTag='';
	$scope.namespace=$location.search()['namespace'];
	$scope.repository=$location.search()['repository'];
	$scope.tagsList=[];
	URL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+$scope.repository+'/tags';
	$scope.deleteTag = function (tag)
	{

			$http.delete(URL+'/'+tag).success(function (data)
			{
				console.log('Deleted tag : '+tag);
				$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
			}).error(function(data){alert('Unable to delete.')});;
	};

	/*This function gets 2 parameters the old tag before editand the new tag after edit.
	 * This function will delete the old tag after getting the image id attached to it, use this image ID
	 * to put the new tag in the repository, thus having the same effect as editing a tag.
	 */
	$scope.changeTag = function (oldTag,newTag)
	{
		$scope.oldTagURL=URL+'/'+oldTag;
		$scope.newTagURL=URL+'/'+newTag;
		$scope.imageID='';
		imageId='\"hello\"';
		console.log('image id fetch url is '+ $scope.oldTagURL);
		console.log('tag putting url is ' + $scope.newTagURL);
		console.log('new tag is '+ newTag);
		$http({method: 'GET', url: $scope.oldTagURL }).success(function(data)
		{
			console.log('Data fetched : '+data);
			imageId='\"'+data.replace(/"/g,'')+'\"';
			$http.delete($scope.oldTagURL).success(function (data)
			{
				$http({method: 'PUT', url: $scope.newTagURL, data: imageId , headers: {"Content-Type": "application/json","Accept": "application/json"}}).success(function(data)
				{
					$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
				}).error(function(data){
				console.log('Unable to set tag for imageID');
				});

			}).error(function(data){alert('Unable to delete.')});

		}).error(function(data){console.log('Unable to get image ID for tag')});

	}

	$http({method: 'GET', url: URL }).success(function(data)
	{
		$scope.results=data;
		numTags=0;
		angular.forEach($scope.results,function(key,value)
		{
			numTags++;
			temp={};
			temp['name']=value;
			temp['id']=numTags;
			$scope.tagsList.push(temp);
		});
	}).error(function(data){alert('Unable to request.')});
});

<|endoftext|>


<commit_before>function InitPreviewSwitchTrait() {
    /**
     * Preview switch for mobile
     */
    this.initPreviewSwitch = function () {
        var dom = new Dom();
        var buttons = '#nav-show-info, #nav-show-preview, #nav-show-form';

        dom.on('click', buttons, function() {
            dom.findAll(buttons).each(function() {
                this.removeClass('active');
            })

            this.addClass('active');
        });

        dom.on('click', '#nav-show-info', function() {
            don.findOne('#doc').removeClass('show-preview');
        });

        dom.on('click', '#nav-show-preview', function() {
            dom.findOne('#doc').addClass('show-preview');
        });
    };
}
<commit_msg>Typo fix<commit_after>function InitPreviewSwitchTrait() {
    /**
     * Preview switch for mobile
     */
    this.initPreviewSwitch = function () {
        var dom = new Dom();
        var buttons = '#nav-show-info, #nav-show-preview, #nav-show-form';

        dom.on('click', buttons, function() {
            dom.findAll(buttons).each(function() {
                this.removeClass('active');
            })

            this.addClass('active');
        });

        dom.on('click', '#nav-show-info', function() {
            dom.findOne('#doc').removeClass('show-preview');
        });

        dom.on('click', '#nav-show-preview', function() {
            dom.findOne('#doc').addClass('show-preview');
        });
    };
}
<|endoftext|>


<commit_before>/*
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
over the plot.

  crosshair: {
    mode: null or "x" or "y" or "xy"
    color: color
    lineWidth: number
  }

Set the mode to one of "x", "y" or "xy". The "x" mode enables a
vertical crosshair that lets you trace the values on the x axis, "y"
enables a horizontal crosshair and "xy" enables them both. "color" is
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),
"lineWidth" is the width of the drawn lines (default is 1).

The plugin also adds two public methods:

  - setCrosshair(pos)

    Set the position of the crosshair. Note that this is cleared if
    the user moves the mouse. "pos" should be on the form { x: xpos,
    y: ypos } (or x2 and y2 if you're using the secondary axes), which
    is coincidentally the same format as what you get from a "plothover"
    event. If "pos" is null, the crosshair is cleared.

  - clearCrosshair()

    Clear the crosshair.

*/

(function ($) {
    var options = {
        crosshair: {
            mode: null, // one of null, "x", "y" or "xy",
            color: "rgba(170, 0, 0, 0.80)",
            lineWidth: 1
        }
    };

    function init(plot) {
        // position of crosshair in pixels
        var crosshair = { x: -1, y: -1 };

        plot.setCrosshair = function setCrosshair(pos) {
            if (!pos)
                crosshair.x = -1;
            else {
                var axes = plot.getAxes();

                crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
                crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
            }

            plot.triggerRedrawOverlay();
        };

        plot.clearCrosshair = plot.setCrosshair; // passes null for pos

        plot.hooks.bindEvents.push(function (plot, eventHolder) {
            if (!plot.getOptions().crosshair.mode)
                return;

            eventHolder.mouseout(function () {
                if (crosshair.x != -1) {
                    crosshair.x = -1;
                    plot.triggerRedrawOverlay();
                }
            });

            eventHolder.mousemove(function (e) {
                if (!plot.getSelection()) {
                    var offset = plot.offset();
                    crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
                    crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
                    plot.triggerRedrawOverlay();
                }
                else
                    crosshair.x = -1; // hide the crosshair while selecting
            });
        });

        plot.hooks.drawOverlay.push(function (plot, ctx) {
            var c = plot.getOptions().crosshair;
            if (!c.mode)
                return;

            var plotOffset = plot.getPlotOffset();

            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);

            if (crosshair.x != -1) {
                ctx.strokeStyle = c.color;
                ctx.lineWidth = c.lineWidth;
                ctx.lineJoin = "round";

                ctx.beginPath();
                if (c.mode.indexOf("x") != -1) {
                    ctx.moveTo(crosshair.x, 0);
                    ctx.lineTo(crosshair.x, plot.height());
                }
                if (c.mode.indexOf("y") != -1) {
                    ctx.moveTo(0, crosshair.y);
                    ctx.lineTo(plot.width(), crosshair.y);
                }
                ctx.stroke();
            }
            ctx.restore();
        });
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'crosshair',
        version: '1.0'
    });
})(jQuery);
<commit_msg>Integrated patch for adding locking feature to the crosshair plugin from Phrogz<commit_after>/*
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
over the plot.

  crosshair: {
    mode: null or "x" or "y" or "xy"
    color: color
    lineWidth: number
  }

Set the mode to one of "x", "y" or "xy". The "x" mode enables a
vertical crosshair that lets you trace the values on the x axis, "y"
enables a horizontal crosshair and "xy" enables them both. "color" is
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),
"lineWidth" is the width of the drawn lines (default is 1).

The plugin also adds four public methods:

  - setCrosshair(pos)

    Set the position of the crosshair. Note that this is cleared if
    the user moves the mouse. "pos" should be on the form { x: xpos,
    y: ypos } (or x2 and y2 if you're using the secondary axes), which
    is coincidentally the same format as what you get from a "plothover"
    event. If "pos" is null, the crosshair is cleared.

  - clearCrosshair()

    Clear the crosshair.

  - lockCrosshair(pos)

    Cause the crosshair to lock to the current location, no longer
    updating if the user moves the mouse. Optionally supply a position
    (passed on to setCrosshair()) to move it to.

    Example usage:
      var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };
      $("#graph").bind("plothover", function (evt, position, item) {
        if (item) {
          // Lock the crosshair to the data point being hovered
          myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] });
        }
        else {
          // Return normal crosshair operation
          myFlot.unlockCrosshair();
        }
      });

  - unlockCrosshair()

    Free the crosshair to move again after locking it.
*/

(function ($) {
    var options = {
        crosshair: {
            mode: null, // one of null, "x", "y" or "xy",
            color: "rgba(170, 0, 0, 0.80)",
            lineWidth: 1
        }
    };

    function init(plot) {
        // position of crosshair in pixels
        var crosshair = { x: -1, y: -1, locked: false };

        plot.setCrosshair = function setCrosshair(pos) {
            if (!pos)
                crosshair.x = -1;
            else {
                var axes = plot.getAxes();

                crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
                crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
            }

            plot.triggerRedrawOverlay();
        };

        plot.clearCrosshair = plot.setCrosshair; // passes null for pos

        plot.lockCrosshair = function lockCrosshair(pos) {
            if (pos)
                plot.setCrosshair(pos);
            crosshair.locked = true;
        }

        plot.unlockCrosshair = function unlockCrosshair() {
            crosshair.locked = false;
        }

        plot.hooks.bindEvents.push(function (plot, eventHolder) {
            if (!plot.getOptions().crosshair.mode)
                return;

            eventHolder.mouseout(function () {
                if (crosshair.x != -1) {
                    crosshair.x = -1;
                    plot.triggerRedrawOverlay();
                }
            });

            eventHolder.mousemove(function (e) {
                if (!plot.getSelection()) {
                    if (!crosshair.locked) {
                        var offset = plot.offset();
                        crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
                        crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
                        plot.triggerRedrawOverlay();
                    }
                }
                else
                    crosshair.x = -1; // hide the crosshair while selecting
            });
        });

        plot.hooks.drawOverlay.push(function (plot, ctx) {
            var c = plot.getOptions().crosshair;
            if (!c.mode)
                return;

            var plotOffset = plot.getPlotOffset();

            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);

            if (crosshair.x != -1) {
                ctx.strokeStyle = c.color;
                ctx.lineWidth = c.lineWidth;
                ctx.lineJoin = "round";

                ctx.beginPath();
                if (c.mode.indexOf("x") != -1) {
                    ctx.moveTo(crosshair.x, 0);
                    ctx.lineTo(crosshair.x, plot.height());
                }
                if (c.mode.indexOf("y") != -1) {
                    ctx.moveTo(0, crosshair.y);
                    ctx.lineTo(plot.width(), crosshair.y);
                }
                ctx.stroke();
            }
            ctx.restore();
        });
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'crosshair',
        version: '1.0'
    });
})(jQuery);
<|endoftext|>


<commit_before>// Javascript for parsing and displaying departure information
var routes = {};
// Replace with InfoPoint URL
var url = "alarmpi.ddns.umass.edu:8080";
var body;
var refresh_id;
var error_check_id;
var stops;
var sort_function;
var allowed_routes = [];
var stop_index = 0;
var REFRESH_TIME = 30000; // 30 seconds between info reloading
var CASCADE_SPEED = 250; // 250ms between cascading routes

// Parse apart query string, conveniently tagged onto jQuery
(function($) {
    $.QueryString = (function(a) {
        if (a == "") return {};
        var b = {};
        for (var i = 0; i < a.length; ++i)
        {
            var p=a[i].split('=');
            if (p.length != 2) continue;
            b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
        }
        return b;
    })(window.location.search.substr(1).split('&'))
})(jQuery);

$(function(){
  body = $('body');
  parseQueryString();
  initBoard();
});

function startErrorRoutine() {
  stopRefreshing();
  body.append('
No Bus Information Available
');
  $('.connectivity_note').removeClass('hidden');
  error_check_id = setInterval(function(){
    console.log("Checking");
    $.ajax({
      url: "http://" + url + "/PublicMessages/GetCurrentMessages",
      success: function(route_data) {
        body.empty();
        console.log("It lives!");
        clearInterval(error_check_id);
        initBoard();
      }
    });
  }, 5000);

}

function parseQueryString() {
  var stop_query_string = $.QueryString["stops"];
  // Check if a query string has been specified
  if (typeof stop_query_string !== "undefined") {
    stops = [];
    var query_parts = stop_query_string.split(" ");
    for (var i = 0; i < query_parts.length; i++) {
      if (query_parts[i]) {
        stops.push(query_parts[i]);
      }
    }
  }
  // If they didn't enter any stops, or they screwed up, default to stop ID 64, the Integrative Learning Center
  if (typeof stops === "undefined" || (typeof stops !== "undefined" && stops.length == 0)) {
    stops = [64];
  }

  var route_query_string = $.QueryString["routes"];

  if (typeof route_query_string !== "undefined") {
    routes = [];
    var query_parts = route_query_string.split(" ");
    for (var i = 0; i < query_parts.length; i++) {
      if (query_parts[i]) {
        allowed_routes.push(query_parts[i]);
      }
    }
  }

  var sort_query_string = $.QueryString["sort"];

  if (typeof sort_query_string !== "undefined") {
    if (sort_query_string == "time") {
      sort_function = function(a, b) {
        return a.Departure.EDT < b.Departure.EDT ? -1 : 1;
      }
    }
  }
}

function initBoard() {
  // Let's start by preloading all of the route info, because when we query
  // departures, we'll only have the route ID
  $.ajax({
    url: "http://" + url + "/routes/getvisibleroutes",
    success: function(route_data) {
    for (var i = 0; i < route_data.length; i++) {
      routes[route_data[i].RouteId] = route_data[i];
    }
    addTables();
    startRefreshing();
  },
  dataType: 'json',
  error: startErrorRoutine});
}

function startRefreshing() {
  // Refresh the board every 30 seconds
  refresh_id = setInterval(function() {
    body.empty();
    addTables();
  }, REFRESH_TIME);
}

function stopRefreshing() {
  clearInterval(refresh_id);
}

function addTables() {
  // There are two separate calls here,
  $.ajax({
    url: "http://" + url + "/stops/get/"+stops[stop_index],
    success: function(stop_info) {
      $.ajax({
        url: "http://" + url + "/stopdepartures/get/" + stops[stop_index],
        success: function(departure_data) {
          // Draw the header for each stop
          body.append('
' + stop_info.Name + "
");
          var infos = getDepartureInfo(departure_data[0].RouteDirections);
          var i = 0;
          // For that soothing cascading effect
          var id = setInterval(function() {
              // If we still have rows to render
              if (i < infos.length) {
                renderRow(infos[i]);
                i++;
              } else { // If not, clear out the timer and move onto the next route
                clearTimeout(id);
                stop_index++;
                // If we run out of stops, reset our index and don't do anything
                if (stop_index < stops.length) {
                  addTables(stops);
                } else {
                  stop_index = 0;
                }
              }
            }, CASCADE_SPEED);
      },
      dataType: 'json',
      error: startErrorRoutine});
    },
    dataType: 'json',
    error: startErrorRoutine});
}

// A bit of a misnomer, we will occassionally render more that one row in here,
// as explained below
function renderRow(info) {
  body.append(
      '
' +
      '
' +
      info.Route.ShortName + " " + info.Departure.Trip.InternetServiceDesc +
      '
' +
      '
' +
      moment(info.Departure.EDT).fromNow(true) +
      '
' +
      '

' +
      '
'
      );
}

function getDepartureInfo(directions) {
  // This is a little tricky. There's a sort of edge case where we want to
  // display information for multiple buses on the same route, that are doing
  // different things. We differentiate them by using their
  // InternetServiceDesc, which will be different. Since the departures are
  // ordered from soonest to furthest away, we care about the first one with
  // a unique InternetServiceDesc, and that's what we're checking here.
  var unique_ISC = [];
  departures = [];
  for (var i = 0; i < directions.length; i++) {
    var direction = directions[i];
    for (var j = 0; j < direction.Departures.length; j++) {
      var departure = direction.Departures[j];
      if ($.inArray(departure.Trip.InternetServiceDesc, unique_ISC) == -1
          && (allowed_routes.length == 0 || $.inArray(route.ShortName, allowed_routes) != -1)
          && moment(departure.EDT).isAfter(Date.now())) {
        unique_ISC.push(departure.Trip.InternetServiceDesc);
        departures.push({Departure: departure, Route: routes[direction.RouteId]});
      }
    }
  }
  if (typeof sort_function !== "undefined") {
    return departures.sort(sort_function);
  } else {
    return departures;
  }
}
<commit_msg>Routes fix<commit_after>// Javascript for parsing and displaying departure information
var routes = {};
// Replace with InfoPoint URL
var url = "alarmpi.ddns.umass.edu:8080";
var body;
var refresh_id;
var error_check_id;
var stops;
var sort_function;
var allowed_routes = [];
var stop_index = 0;
var REFRESH_TIME = 30000; // 30 seconds between info reloading
var CASCADE_SPEED = 250; // 250ms between cascading routes

// Parse apart query string, conveniently tagged onto jQuery
(function($) {
    $.QueryString = (function(a) {
        if (a == "") return {};
        var b = {};
        for (var i = 0; i < a.length; ++i)
        {
            var p=a[i].split('=');
            if (p.length != 2) continue;
            b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
        }
        return b;
    })(window.location.search.substr(1).split('&'))
})(jQuery);

$(function(){
  body = $('body');
  parseQueryString();
  initBoard();
});

function startErrorRoutine() {
  stopRefreshing();
  body.append('
No Bus Information Available
');
  $('.connectivity_note').removeClass('hidden');
  error_check_id = setInterval(function(){
    console.log("Checking");
    $.ajax({
      url: "http://" + url + "/PublicMessages/GetCurrentMessages",
      success: function(route_data) {
        body.empty();
        console.log("It lives!");
        clearInterval(error_check_id);
        initBoard();
      }
    });
  }, 5000);

}

function parseQueryString() {
  var stop_query_string = $.QueryString["stops"];
  // Check if a query string has been specified
  if (typeof stop_query_string !== "undefined") {
    stops = [];
    var query_parts = stop_query_string.split(" ");
    for (var i = 0; i < query_parts.length; i++) {
      if (query_parts[i]) {
        stops.push(query_parts[i]);
      }
    }
  }
  // If they didn't enter any stops, or they screwed up, default to stop ID 64, the Integrative Learning Center
  if (typeof stops === "undefined" || (typeof stops !== "undefined" && stops.length == 0)) {
    stops = [64];
  }

  var route_query_string = $.QueryString["routes"];

  if (typeof route_query_string !== "undefined") {
    routes = [];
    var query_parts = route_query_string.split(" ");
    for (var i = 0; i < query_parts.length; i++) {
      if (query_parts[i]) {
        allowed_routes.push(query_parts[i]);
      }
    }
  }

  var sort_query_string = $.QueryString["sort"];

  if (typeof sort_query_string !== "undefined") {
    if (sort_query_string == "time") {
      sort_function = function(a, b) {
        return a.Departure.EDT < b.Departure.EDT ? -1 : 1;
      }
    }
  }
}

function initBoard() {
  // Let's start by preloading all of the route info, because when we query
  // departures, we'll only have the route ID
  $.ajax({
    url: "http://" + url + "/routes/getvisibleroutes",
    success: function(route_data) {
    for (var i = 0; i < route_data.length; i++) {
      routes[route_data[i].RouteId] = route_data[i];
    }
    addTables();
    startRefreshing();
  },
  dataType: 'json',
  error: startErrorRoutine});
}

function startRefreshing() {
  // Refresh the board every 30 seconds
  refresh_id = setInterval(function() {
    body.empty();
    addTables();
  }, REFRESH_TIME);
}

function stopRefreshing() {
  clearInterval(refresh_id);
}

function addTables() {
  // There are two separate calls here,
  $.ajax({
    url: "http://" + url + "/stops/get/"+stops[stop_index],
    success: function(stop_info) {
      $.ajax({
        url: "http://" + url + "/stopdepartures/get/" + stops[stop_index],
        success: function(departure_data) {
          // Draw the header for each stop
          body.append('
' + stop_info.Name + "
");
          var infos = getDepartureInfo(departure_data[0].RouteDirections);
          var i = 0;
          // For that soothing cascading effect
          var id = setInterval(function() {
              // If we still have rows to render
              if (i < infos.length) {
                renderRow(infos[i]);
                i++;
              } else { // If not, clear out the timer and move onto the next route
                clearTimeout(id);
                stop_index++;
                // If we run out of stops, reset our index and don't do anything
                if (stop_index < stops.length) {
                  addTables(stops);
                } else {
                  stop_index = 0;
                }
              }
            }, CASCADE_SPEED);
      },
      dataType: 'json',
      error: startErrorRoutine});
    },
    dataType: 'json',
    error: startErrorRoutine});
}

// A bit of a misnomer, we will occassionally render more that one row in here,
// as explained below
function renderRow(info) {
  body.append(
      '
' +
      '
' +
      info.Route.ShortName + " " + info.Departure.Trip.InternetServiceDesc +
      '
' +
      '
' +
      moment(info.Departure.EDT).fromNow(true) +
      '
' +
      '

' +
      '
'
      );
}

function getDepartureInfo(directions) {
  // This is a little tricky. There's a sort of edge case where we want to
  // display information for multiple buses on the same route, that are doing
  // different things. We differentiate them by using their
  // InternetServiceDesc, which will be different. Since the departures are
  // ordered from soonest to furthest away, we care about the first one with
  // a unique InternetServiceDesc, and that's what we're checking here.
  var unique_ISC = [];
  departures = [];
  for (var i = 0; i < directions.length; i++) {
    var direction = directions[i];
    var route = routes[direction.RouteId];
    for (var j = 0; j < direction.Departures.length; j++) {
      var departure = direction.Departures[j];
      if ($.inArray(departure.Trip.InternetServiceDesc, unique_ISC) == -1
          && (allowed_routes.length == 0 || $.inArray(route.ShortName, allowed_routes) != -1)
          && moment(departure.EDT).isAfter(Date.now())) {
        unique_ISC.push(departure.Trip.InternetServiceDesc);
        departures.push({Departure: departure, Route: route});
      }
    }
  }
  if (typeof sort_function !== "undefined") {
    return departures.sort(sort_function);
  } else {
    return departures;
  }
}
<|endoftext|>


<commit_before>angular.module('main').
	factory('wizard', ['$rootScope', '$http', '$q', 'apiClient', 'cache', 'notification', 'ftrees', '$window',
	function($rootScope, $http, $q, apiClient, cache, notification, ftrees, $window) {

		/**
		 * @ngdoc service
		 * @name wizard
		 *
		 * @description
		 * The Wizard service is in charge of wizard-searching & of keeping search state.
		 */
		var wizard = {

			/**
			 * @ngdoc property
			 * @name wizard#in_progress
			 *
			 * @description
			 * Indicates that the wizard service is busy.
			 */
			in_progress: false,

			/**
			 * @ngdoc property
			 * @name wizard#failed
			 *
			 * @description
			 * Indicates that a wizard operation has failed.
			 */
			failed: false,

			/**
			 * @ngdoc property
			 * @name wizard#query
			 *
			 * @description
			 * An object representing the current wizard query.
			 * Once a wizard search is triggered, this query will be used.
			 * The query holds two strings: a name and a place.
			 */
			query: {
				name: '',
				place: ''
			},

			/**
			 * @ngdoc property
			 * @name wizard#result
			 *
			 * @description
			 * The result of the last wizard search.
			 */
			result: {},

			/**
			 * @ngdoc property
			 * @name wizard#search_status
			 *
			 * @description
			 * Wizard search status.
			 */
			search_status: '',

			/**
			 * @ngdoc property
			 * @name wizard#last_search
			 *
			 * @description
			 * Last wizard search.
			 */
			last_search: {
				name: '',
				place: ''
			},

			/**
			 * @ngdoc method
			 * @name wizard#clear
			 *
			 * @description
			 * Clear wizard result and search status.
			 */
			clear: function() {
				this.result = {};
				this.search_status = '';
			},

			/**
			 * @ngdoc method
			 * @name wizard#search
			 *
			 * @description
			 * Triggers a wizard search using the wizard query.
			 * Sets search_status, last_search, result.
			 * Filters (live) individual data.
			 * It also handles notifications.
			 *
			 * @returns
			 * {Promise}
			 */
			search: function() {
	  			if ( !(this.in_progress) ) {

	  				if ($window.sessionStorage.wizard_result) {
	  					$window.sessionStorage.removeItem("wizard_result");
	  				}

	  				this.in_progress = true;

					notification.loading(true);

		  			var self = this,
		  				query_params = {},
		  				query = this.query,
		  				search_promise,
		  				deferred = $q.defer();

		  			// make sure there are no empty strings in the request query params
		  			if (query.name) {
		  				query_params.name = query.name;
		  			}
		  			if (query.place) {
		  				query_params.place = query.place;
		  			}

		  			$http.get(apiClient.urls.wizard_search, {
						params: query_params
					}).
					success(function(result) {
						// set search status
						var search_status;
						notification.loading(false);

		                if ( result.name.isNotEmpty() || result.place.isNotEmpty())  {

		                	if (result.name.isNotEmpty()) {
		                		cache.put(result.name);
		                	}

	                		if (result.place.isNotEmpty()) {
		                		cache.put(result.place)
		                    }

		                    if ( result.name.isNotEmpty() && result.place.isEmpty() ) {
		                        self.search_status = 'bingo-name';
								if (query_params.place)
									notification.put(13);
		                    }
		                    else if ( result.name.isEmpty() && result.place.isNotEmpty() ) {
		                        self.search_status = 'bingo-place';
								if (query_params.name)
									notification.put(14);
		                    }
		                    else {
		                        self.search_status = 'bingo';
		                    }
		                }
		                else {
		                    self.search_status =  'none';
		                    notification.put(12);
		                }

						self.result = result;
						$window.sessionStorage.setItem('wizard_result', JSON.stringify(result));
						self.last_search.name = self.query.name;
						self.last_search.place = self.query.place;

						deferred.resolve(search_status);
					}).
					error(function() {
						notification.put(11);
		                self.failed = true;
						deferred.reject();
					}).
		  			finally(function() {
						self.in_progress = false;
						$rootScope.$broadcast('wizard-search-end');
					});

		  			return deferred.promise;
			  	}
			}
		};

		return wizard;
	}]);
<commit_msg>to not display wizard failed search error message when taken to tree search<commit_after>angular.module('main').
	factory('wizard', ['$rootScope', '$http', '$q', 'apiClient', 'cache', 'notification', 'ftrees', '$window',
	function($rootScope, $http, $q, apiClient, cache, notification, ftrees, $window) {

		/**
		 * @ngdoc service
		 * @name wizard
		 *
		 * @description
		 * The Wizard service is in charge of wizard-searching & of keeping search state.
		 */
		var wizard = {

			/**
			 * @ngdoc property
			 * @name wizard#in_progress
			 *
			 * @description
			 * Indicates that the wizard service is busy.
			 */
			in_progress: false,

			/**
			 * @ngdoc property
			 * @name wizard#failed
			 *
			 * @description
			 * Indicates that a wizard operation has failed.
			 */
			failed: false,

			/**
			 * @ngdoc property
			 * @name wizard#query
			 *
			 * @description
			 * An object representing the current wizard query.
			 * Once a wizard search is triggered, this query will be used.
			 * The query holds two strings: a name and a place.
			 */
			query: {
				name: '',
				place: ''
			},

			/**
			 * @ngdoc property
			 * @name wizard#result
			 *
			 * @description
			 * The result of the last wizard search.
			 */
			result: {},

			/**
			 * @ngdoc property
			 * @name wizard#search_status
			 *
			 * @description
			 * Wizard search status.
			 */
			search_status: '',

			/**
			 * @ngdoc property
			 * @name wizard#last_search
			 *
			 * @description
			 * Last wizard search.
			 */
			last_search: {
				name: '',
				place: ''
			},

			/**
			 * @ngdoc method
			 * @name wizard#clear
			 *
			 * @description
			 * Clear wizard result and search status.
			 */
			clear: function() {
				this.result = {};
				this.search_status = '';
			},

			/**
			 * @ngdoc method
			 * @name wizard#search
			 *
			 * @description
			 * Triggers a wizard search using the wizard query.
			 * Sets search_status, last_search, result.
			 * Filters (live) individual data.
			 * It also handles notifications.
			 *
			 * @returns
			 * {Promise}
			 */
			search: function() {
	  			if ( !(this.in_progress) ) {

	  				if ($window.sessionStorage.wizard_result) {
	  					$window.sessionStorage.removeItem("wizard_result");
	  				}

	  				this.in_progress = true;

					notification.loading(true);

		  			var self = this,
		  				query_params = {},
		  				query = this.query,
		  				search_promise,
		  				deferred = $q.defer();

		  			// make sure there are no empty strings in the request query params
		  			if (query.name) {
		  				query_params.name = query.name;
		  			}
		  			if (query.place) {
		  				query_params.place = query.place;
		  			}

		  			$http.get(apiClient.urls.wizard_search, {
						params: query_params
					}).
					success(function(result) {
						// set search status
						var search_status;
						notification.loading(false);

		                if ( result.name.isNotEmpty() || result.place.isNotEmpty())  {

		                	if (result.name.isNotEmpty()) {
		                		cache.put(result.name);
		                	}

	                		if (result.place.isNotEmpty()) {
		                		cache.put(result.place)
		                    }

		                    if ( result.name.isNotEmpty() && result.place.isEmpty() ) {
		                        self.search_status = 'bingo-name';
								if (query_params.place)
									notification.put(13);
		                    }
		                    else if ( result.name.isEmpty() && result.place.isNotEmpty() ) {
		                        self.search_status = 'bingo-place';
								if (query_params.name)
									notification.put(14);
		                    }
		                    else {
		                        self.search_status = 'bingo';
		                    }
		                }
		                else {
		                    self.search_status =  'none';
		                }

						self.result = result;
						$window.sessionStorage.setItem('wizard_result', JSON.stringify(result));
						self.last_search.name = self.query.name;
						self.last_search.place = self.query.place;

						deferred.resolve(search_status);
					}).
					error(function() {
						notification.put(11);
		                self.failed = true;
						deferred.reject();
					}).
		  			finally(function() {
						self.in_progress = false;
						$rootScope.$broadcast('wizard-search-end');
					});

		  			return deferred.promise;
			  	}
			}
		};

		return wizard;
	}]);
<|endoftext|>


<commit_before>import * as yup from 'yup';
import i18next from '../../core/language';
import map from 'lodash/map';
import moment from 'moment';
import { MGDL_UNITS, MMOLL_UNITS, MS_IN_DAY } from '../../core/constants';

import {
  dateFormat,
  defaultUnits,
  phoneRegex,
  revisionStates,
  pumpDeviceOptions,
  cgmDeviceOptions,
  insulinModelOptions,
  pumpRanges,
  typeOptions,
  sexOptions,
  trainingOptions,
  validCountryCodes,
} from './prescriptionFormConstants';

const t = i18next.t.bind(i18next);

export default (devices, pumpId, bgUnits = defaultUnits.bloodGlucose, values) => {
  const pump = find(devices.pumps, { id: pumpId });
  const ranges = pumpRanges(pump, bgUnits, values);

  const deviceOptions = {
    pumps: pumpDeviceOptions(devices),
    cgms: cgmDeviceOptions(devices),
  }

  const rangeError = key => t('Please select a value between {{min}}-{{max}}', {
    min: ranges[key].min,
    max: ranges[key].max,
  });

  return yup.object().shape({
    id: yup.string(),
    state: yup.string()
      .oneOf(revisionStates, t('Please select a valid option')),
    accountType: yup.string()
      .oneOf(map(typeOptions, 'value'), t('Please select a valid option'))
      .required(t('Account type is required')),
    firstName: yup.string()
      .required(t('First name is required')),
    lastName: yup.string()
      .required(t('Last name is required')),
    caregiverFirstName: yup.string().when('accountType', {
      is: 'caregiver',
      then: yup.string().required(t('First name is required')),
    }),
    caregiverLastName: yup.string().when('accountType', {
      is: 'caregiver',
      then: yup.string().required(t('Last name is required')),
    }),
    birthday: yup.string()
      .test('matchesDateFormat', t('Please enter a valid date in the requested format'), value => moment(value, dateFormat, true).isValid())
      .test('isPastDate', t('Please enter a date prior to today'), value => value < moment().format(dateFormat))
      .required(t('Patient\'s birthday is required')),
    email: yup.string()
      .email(t('Please enter a valid email address'))
      .required(t('Email address is required')),
    emailConfirm: yup.string()
      .oneOf([yup.ref('email')], t('Email address confirmation does not match'))
      .required(t('Email confirmation is required')),
    phoneNumber: yup.object().shape({
      countryCode: yup.number()
        .integer()
        .oneOf(validCountryCodes, t('Please set a valid country code'))
        .required(t('Country code is required')),
      number: yup.string()
        .matches(phoneRegex, t('Please enter a valid phone number'))
        .required(t('Patient phone number is required')),
    }),
    mrn: yup.string()
      .required(t('Patient MRN number is required')),
    sex: yup.string()
      .oneOf(map(sexOptions, 'value'), t('Please select a valid option'))
      .required(t('Patient gender is required')),
    initialSettings: yup.object().shape({
      bloodGlucoseUnits: yup.string()
        .oneOf([MGDL_UNITS, MMOLL_UNITS], t('Please set a valid blood glucose units option'))
        .default(bgUnits),
      pumpId: yup.string()
        .oneOf(map(deviceOptions.pumps, 'value'))
        .required(t('A pump type must be specified')),
      cgmId: yup.string()
        .oneOf(map(deviceOptions.cgms, 'value'))
        .required(t('A cgm type must be specified')),
      insulinModel: yup.string()
        .oneOf(map(insulinModelOptions, 'value'))
        .required(t('An insulin model must be specified')),
      glucoseSafetyLimit: yup.number()
        .min(ranges.glucoseSafetyLimit.min, rangeError('glucoseSafetyLimit'))
        .max(ranges.glucoseSafetyLimit.max, rangeError('glucoseSafetyLimit'))
        .required(t('Suspend threshold is required')),
      basalRateMaximum: yup.object().shape({
        value: yup.number()
          .min(ranges.basalRateMaximum.min, rangeError('basalRateMaximum'))
          .max(ranges.basalRateMaximum.max, rangeError('basalRateMaximum'))
          .required(t('Max basal rate is required')),
        units: yup.string()
          .default(defaultUnits.basalRate),
      }),
      bolusAmountMaximum: yup.object().shape({
        value: yup.number()
          .min(ranges.bolusAmountMaximum.min, rangeError('bolusAmountMaximum'))
          .max(ranges.bolusAmountMaximum.max, rangeError('bolusAmountMaximum'))
          .required(t('Max bolus amount is required')),
        units: yup.string()
          .default(defaultUnits.bolusAmount),
      }),
      bloodGlucoseTargetSchedule: yup.array().of(
        yup.object().shape({
          high: yup.number()
            .min(yup.ref('low') || ranges.bloodGlucoseTarget.min, rangeError('bloodGlucoseTarget').replace(ranges.bloodGlucoseTarget.min, '${min}'))
            .max(ranges.bloodGlucoseTarget.max, rangeError('bloodGlucoseTarget'))
            .required(t('High target is required')),
          low: yup.number()
            .min(ranges.bloodGlucoseTarget.min, rangeError('bloodGlucoseTarget'))
            .max(ranges.bloodGlucoseTarget.max, rangeError('bloodGlucoseTarget'))
            .required(t('Low target is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      bloodGlucoseTargetPhysicalActivity: yup.object().shape({
        high: yup.number()
          .min(yup.ref('low') || ranges.bloodGlucoseTargetPhysicalActivity.min, rangeError('bloodGlucoseTargetPhysicalActivity').replace(ranges.bloodGlucoseTargetPhysicalActivity.min, '${min}'))
          .max(ranges.bloodGlucoseTargetPhysicalActivity.max, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .required(t('High target is required')),
        low: yup.number()
          .min(ranges.bloodGlucoseTargetPhysicalActivity.min, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .max(ranges.bloodGlucoseTargetPhysicalActivity.max, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .required(t('Low target is required')),
      }),
      bloodGlucoseTargetPreprandial: yup.object().shape({
        high: yup.number()
          .min(yup.ref('low') || ranges.bloodGlucoseTargetPreprandial.min, rangeError('bloodGlucoseTargetPreprandial').replace(ranges.bloodGlucoseTargetPreprandial.min, '${min}'))
          .max(ranges.bloodGlucoseTargetPreprandial.max, rangeError('bloodGlucoseTargetPreprandial'))
          .required(t('High target is required')),
        low: yup.number()
          .min(ranges.bloodGlucoseTargetPreprandial.min, rangeError('bloodGlucoseTargetPreprandial'))
          .max(ranges.bloodGlucoseTargetPreprandial.max, rangeError('bloodGlucoseTargetPreprandial'))
          .required(t('Low target is required')),
      }),
      basalRateSchedule: yup.array().of(
        yup.object().shape({
          rate: yup.number()
            .min(ranges.basalRate.min, rangeError('basalRate'))
            .max(ranges.basalRate.max, rangeError('basalRate'))
            .required(t('Basal rate is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      carbohydrateRatioSchedule: yup.array().of(
        yup.object().shape({
          amount: yup.number()
            .min(ranges.carbRatio.min, rangeError('carbRatio'))
            .max(ranges.carbRatio.max, rangeError('carbRatio'))
            .required(t('Insulin-to-carb ratio is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      insulinSensitivitySchedule: yup.array().of(
        yup.object().shape({
          amount: yup.number()
            .min(ranges.insulinSensitivityFactor.min, rangeError('insulinSensitivityFactor'))
            .max(ranges.insulinSensitivityFactor.max, rangeError('insulinSensitivityFactor'))
            .required(t('Sensitivity factor is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
    }),
    training: yup.string()
      .oneOf(map(trainingOptions, 'value'), t('Please select a valid option'))
      .required(t('Training type is required')),
    therapySettingsReviewed: yup.boolean()
      .test('isTrue', t('Please confirm the therapy settings for this patient'), value => (value === true)),
  });
};
<commit_msg>[WEB-1074] Allow caregiver name fields to validate when undefined and account type is not caregiver<commit_after>import * as yup from 'yup';
import i18next from '../../core/language';
import map from 'lodash/map';
import moment from 'moment';
import { MGDL_UNITS, MMOLL_UNITS, MS_IN_DAY } from '../../core/constants';

import {
  dateFormat,
  defaultUnits,
  phoneRegex,
  revisionStates,
  pumpDeviceOptions,
  cgmDeviceOptions,
  insulinModelOptions,
  pumpRanges,
  typeOptions,
  sexOptions,
  trainingOptions,
  validCountryCodes,
} from './prescriptionFormConstants';

const t = i18next.t.bind(i18next);

export default (devices, pumpId, bgUnits = defaultUnits.bloodGlucose, values) => {
  const pump = find(devices.pumps, { id: pumpId });
  const ranges = pumpRanges(pump, bgUnits, values);

  const deviceOptions = {
    pumps: pumpDeviceOptions(devices),
    cgms: cgmDeviceOptions(devices),
  }

  const rangeError = key => t('Please select a value between {{min}}-{{max}}', {
    min: ranges[key].min,
    max: ranges[key].max,
  });

  return yup.object().shape({
    id: yup.string(),
    state: yup.string()
      .oneOf(revisionStates, t('Please select a valid option')),
    accountType: yup.string()
      .oneOf(map(typeOptions, 'value'), t('Please select a valid option'))
      .required(t('Account type is required')),
    firstName: yup.string()
      .required(t('First name is required')),
    lastName: yup.string()
      .required(t('Last name is required')),
    caregiverFirstName: yup.mixed().notRequired().when('accountType', {
      is: 'caregiver',
      then: yup.string().required(t('First name is required')),
    }),
    caregiverLastName: yup.mixed().notRequired().when('accountType', {
      is: 'caregiver',
      then: yup.string().required(t('Last name is required')),
    }),
    birthday: yup.string()
      .test('matchesDateFormat', t('Please enter a valid date in the requested format'), value => moment(value, dateFormat, true).isValid())
      .test('isPastDate', t('Please enter a date prior to today'), value => value < moment().format(dateFormat))
      .required(t('Patient\'s birthday is required')),
    email: yup.string()
      .email(t('Please enter a valid email address'))
      .required(t('Email address is required')),
    emailConfirm: yup.string()
      .oneOf([yup.ref('email')], t('Email address confirmation does not match'))
      .required(t('Email confirmation is required')),
    phoneNumber: yup.object().shape({
      countryCode: yup.number()
        .integer()
        .oneOf(validCountryCodes, t('Please set a valid country code'))
        .required(t('Country code is required')),
      number: yup.string()
        .matches(phoneRegex, t('Please enter a valid phone number'))
        .required(t('Patient phone number is required')),
    }),
    mrn: yup.string()
      .required(t('Patient MRN number is required')),
    sex: yup.string()
      .oneOf(map(sexOptions, 'value'), t('Please select a valid option'))
      .required(t('Patient gender is required')),
    initialSettings: yup.object().shape({
      bloodGlucoseUnits: yup.string()
        .oneOf([MGDL_UNITS, MMOLL_UNITS], t('Please set a valid blood glucose units option'))
        .default(bgUnits),
      pumpId: yup.string()
        .oneOf(map(deviceOptions.pumps, 'value'))
        .required(t('A pump type must be specified')),
      cgmId: yup.string()
        .oneOf(map(deviceOptions.cgms, 'value'))
        .required(t('A cgm type must be specified')),
      insulinModel: yup.string()
        .oneOf(map(insulinModelOptions, 'value'))
        .required(t('An insulin model must be specified')),
      glucoseSafetyLimit: yup.number()
        .min(ranges.glucoseSafetyLimit.min, rangeError('glucoseSafetyLimit'))
        .max(ranges.glucoseSafetyLimit.max, rangeError('glucoseSafetyLimit'))
        .required(t('Suspend threshold is required')),
      basalRateMaximum: yup.object().shape({
        value: yup.number()
          .min(ranges.basalRateMaximum.min, rangeError('basalRateMaximum'))
          .max(ranges.basalRateMaximum.max, rangeError('basalRateMaximum'))
          .required(t('Max basal rate is required')),
        units: yup.string()
          .default(defaultUnits.basalRate),
      }),
      bolusAmountMaximum: yup.object().shape({
        value: yup.number()
          .min(ranges.bolusAmountMaximum.min, rangeError('bolusAmountMaximum'))
          .max(ranges.bolusAmountMaximum.max, rangeError('bolusAmountMaximum'))
          .required(t('Max bolus amount is required')),
        units: yup.string()
          .default(defaultUnits.bolusAmount),
      }),
      bloodGlucoseTargetSchedule: yup.array().of(
        yup.object().shape({
          high: yup.number()
            .min(yup.ref('low') || ranges.bloodGlucoseTarget.min, rangeError('bloodGlucoseTarget').replace(ranges.bloodGlucoseTarget.min, '${min}'))
            .max(ranges.bloodGlucoseTarget.max, rangeError('bloodGlucoseTarget'))
            .required(t('High target is required')),
          low: yup.number()
            .min(ranges.bloodGlucoseTarget.min, rangeError('bloodGlucoseTarget'))
            .max(ranges.bloodGlucoseTarget.max, rangeError('bloodGlucoseTarget'))
            .required(t('Low target is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      bloodGlucoseTargetPhysicalActivity: yup.object().shape({
        high: yup.number()
          .min(yup.ref('low') || ranges.bloodGlucoseTargetPhysicalActivity.min, rangeError('bloodGlucoseTargetPhysicalActivity').replace(ranges.bloodGlucoseTargetPhysicalActivity.min, '${min}'))
          .max(ranges.bloodGlucoseTargetPhysicalActivity.max, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .required(t('High target is required')),
        low: yup.number()
          .min(ranges.bloodGlucoseTargetPhysicalActivity.min, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .max(ranges.bloodGlucoseTargetPhysicalActivity.max, rangeError('bloodGlucoseTargetPhysicalActivity'))
          .required(t('Low target is required')),
      }),
      bloodGlucoseTargetPreprandial: yup.object().shape({
        high: yup.number()
          .min(yup.ref('low') || ranges.bloodGlucoseTargetPreprandial.min, rangeError('bloodGlucoseTargetPreprandial').replace(ranges.bloodGlucoseTargetPreprandial.min, '${min}'))
          .max(ranges.bloodGlucoseTargetPreprandial.max, rangeError('bloodGlucoseTargetPreprandial'))
          .required(t('High target is required')),
        low: yup.number()
          .min(ranges.bloodGlucoseTargetPreprandial.min, rangeError('bloodGlucoseTargetPreprandial'))
          .max(ranges.bloodGlucoseTargetPreprandial.max, rangeError('bloodGlucoseTargetPreprandial'))
          .required(t('Low target is required')),
      }),
      basalRateSchedule: yup.array().of(
        yup.object().shape({
          rate: yup.number()
            .min(ranges.basalRate.min, rangeError('basalRate'))
            .max(ranges.basalRate.max, rangeError('basalRate'))
            .required(t('Basal rate is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      carbohydrateRatioSchedule: yup.array().of(
        yup.object().shape({
          amount: yup.number()
            .min(ranges.carbRatio.min, rangeError('carbRatio'))
            .max(ranges.carbRatio.max, rangeError('carbRatio'))
            .required(t('Insulin-to-carb ratio is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
      insulinSensitivitySchedule: yup.array().of(
        yup.object().shape({
          amount: yup.number()
            .min(ranges.insulinSensitivityFactor.min, rangeError('insulinSensitivityFactor'))
            .max(ranges.insulinSensitivityFactor.max, rangeError('insulinSensitivityFactor'))
            .required(t('Sensitivity factor is required')),
          start: yup.number()
            .integer()
            .min(0)
            .max(MS_IN_DAY)
            .required(t('Start time is required')),
        }),
      ),
    }),
    training: yup.string()
      .oneOf(map(trainingOptions, 'value'), t('Please select a valid option'))
      .required(t('Training type is required')),
    therapySettingsReviewed: yup.boolean()
      .test('isTrue', t('Please confirm the therapy settings for this patient'), value => (value === true)),
  });
};
<|endoftext|>


<commit_before>import { parser as saxParser } from 'sax';

function isAllowedType(type) {
  switch(type) {
    case 'text': case 'opentag': case 'closetag': case 'doctype':
    case 'processinginstruction': case 'attribute': case 'comment':
    case 'opencdata': case 'closecdata': case 'opennamespace':
    case 'closenamespace': case 'opentagstart': return true;
    default: return false;
  }
}

function clone(node) {
  const out = {};
  for(let key in node) {
    const value = node[key];
    if(typeof value === 'object') {
      out[key] = clone(value);
    } else {
      out[key] = value;
    }
  }
  return out;
}

export function makePulley(xml, options) {
  if(!options) options = {};
  const types = options.types || ['opentag', 'closetag', 'text'];
  const queue = [];
  const parser = saxParser(true, {
    xmlns: options.xmlns,
    position: false
  });
  const skipWS = options.skipWhitespaceOnly;
  const trim = options.trim, normalize = options.normalize;
  const textOpts = (t) => {
    if(trim)
      t = t.trim();
    if(normalize)
      t = t.replace(/\s+/g, " ")
    return t;
  };
  let text = null, rawText = null, wsText = null, wsRawText = null;
  const flushText = () => {
    if(skipWS && wsText !== null) {
      queue.push({
        type: 'wstext',
        text: wsText,
        rawText: wsRawText,
        wsHasNext: text !== null
      });
      wsText = wsRawText = null;
    }
    if(text !== null) {
      queue.push({
        type: 'text',
        text,
        rawText
      });
      text = rawText = null;
    }
  };
  parser.onerror = (err) => {
    throw err;
  };
  types.forEach((type) => {
    if(type === 'text') {
      parser.ontext = (t) => {
        const pt = textOpts(t);
        if(skipWS) {
          if(wsText) {
            wsText += pt; wsRawText += t;
          } else {
            wsText = pt; wsRawText = t;
          }
        }
        if(!skipWS || /\S/.test(t)) {
          if(text) {
            text += pt; rawText += t;
          } else {
            text = pt; rawText = t;
          }
        }
      };
      parser.oncdata = (t) => {
        if(text) {
          text += t; rawText += t;
        } else {
          text = rawText = t;
        }
      };
    } else if(type === 'comment') {
      parser.oncomment = (t) => {
        flushText();
        queue.push({
          type: 'comment',
          text: textOpts(t),
          rawText: t
        });
      }
    } else if(type === 'doctype') {
      parser.ondoctype = (t) => {
        flushText();
        queue.push({
          type: 'doctype',
          text: t
        });
      }
    } else if(type === 'closetag') {
      parser.onclosetag = (t) => {
        flushText();
        queue.push({
          type: 'closetag',
          name: t
        });
      }
    } else if(type === 'opencdata' || type === 'closecdata') {
      parser['on'+type] = (data) => {
        flushText();
        queue.push({ type: type });
      }
    } else if(isAllowedType(type)) {
      parser['on'+type] = (data) => {
        flushText();
        data = clone(data);
        data.type = type;
        queue.push(data);
      }
    } else {
      throw Error(`${type} isn't an allowed type!`);
    }
  });
  parser.write(xml).close();
  flushText();
  queue.reverse();

  return constructPulley(queue, skipWS);
}

function constructPulley(queue, skipWS, checkoutcb) {
  let self;

  const next = skipWS ?
    () => {
      let out;
      while((out = queue.pop()) && out.type === 'wstext') {  }
      return out;
    } :
    () => queue.pop();
  const peek = skipWS ?
    () => {
      for(let i = queue.length - 1; i >= 0; --i) {
        const v = queue[i];
        if(v.type !== 'wstext') return v;
      }
    } :
    () => queue[queue.length - 1];

  const nextText = () => {
    const v = queue[queue.length - 1];
    if(v && v.type === 'text') {
      return queue.pop();
    } else if(v && v.type === 'wstext') {
      queue.pop();
      if(v.wsHasNext) queue.pop();
      return { type: 'text', text: v.text, rawText: v.rawText };
    } else {
      return { type: 'text', text: '', rawText: '' };
    }
  };
  const peekText = () => {
    const v = queue[queue.length - 1];
    if(v && v.type === 'text') {
      return v;
    } else if(v && v.type === 'wstext') {
      return { type: 'text', text: v.text, rawText: v.rawText };
    } else {
      return { type: 'text', text: '', rawText: '' };
    }
  };

  const check = (type, error) => {
    const out = peek();
    assertType(out, type, error);
    return out;
  };
  const checkName = (name, type, wrongNameError, wrongTypeError) => {
    type = type || 'opentag';
    const out = peek();
    assertType(out, type, wrongTypeError || wrongNameError);
    assertName(out, name, wrongNameError);
    return out;
  };

  const expect = (type, error) => {
    const out = check(type, error);
    next();
    return out;
  };
  const expectName = (name, type, wrongNameError, wrongTypeError) => {
    const out = checkName(name, type, wrongNameError, wrongTypeError);
    next();
    return out;
  };

  const loop = (callback, endType) => {
    endType = endType || 'closetag';
    let node;
    while((node = peek()) && node.type !== endType) {
      if(callback(self))
        break;
    }
  };
  const loopTag = (callback, name) => {
    const tag = name ? expectName(name) : expect('opentag');
    let node;
    while((node = peek()) && node.type !== 'closetag') {
      callback(self, tag);
    }
    expectName(tag.name, 'closetag');
    return tag;
  };

  const skipTag = (name) => {
    return loopTag((pulley) => {
      const tag = pulley.peek();
      if(tag.type === 'opentag') {
        pulley.skipTag(tag.name);
      } else {
        pulley.next();
      }
    }, name);
  };

  const _checkoutcb = (queue2) => {
    queue = queue2;
    return self;
  };
  const checkin = () => constructPulley(queue.slice(), skipWS, _checkoutcb);
  const checkout = checkoutcb ?
    () => {
      const parent = checkoutcb(queue);
      queue = [];
      return parent;
    } :
    () => {
      throw Error("Can't check out a pulley that wasn't checked in!");
    };

  return self = {
    next,
    peek,
    nextText,
    peekText,
    check,
    checkName,
    expect,
    expectName,
    loop,
    loopTag,
    skipTag,
    checkin,
    checkout
  };
}

export function assertType(node, type, error) {
  if(node === undefined) {
    throw error || Error(`Expected ${type}; got end of file!`);
  } else if(node.type !== type) {
    throw error || Error(`Expected ${type}; got ${node.type}: ${nodeRepr(node)}!`);
  }
}
export function assertName(tag, name, error) {
  if(tag.name !== name) {
    throw error ||
          Error(`${tag.type} had name ${tag.name} instead of ${name}!`);
  }
}

export function nodeRepr(tag) {
  switch(tag.type) {
    case 'text': case 'comment': return `"${tag.text}"`;
    case 'opentag': case 'opentagstart': return `<${tag.name}>`;
    case 'closetag': return `</${tag.name}>`;
    case 'doctype': return `<!${tag.text}>`;
    case 'processinginstruction': return `<?${tag.name} ${tag.body}?>`;
    case 'attribute': return `${tag.name}="${tag.value}"`;
    default:
  }
}
<commit_msg>Made it possible to select the type recognized as an opening tag<commit_after>import { parser as saxParser } from 'sax';

function isAllowedType(type) {
  switch(type) {
    case 'text': case 'opentag': case 'closetag': case 'doctype':
    case 'processinginstruction': case 'attribute': case 'comment':
    case 'opencdata': case 'closecdata': case 'opennamespace':
    case 'closenamespace': case 'opentagstart': return true;
    default: return false;
  }
}

function clone(node) {
  const out = {};
  for(let key in node) {
    const value = node[key];
    if(typeof value === 'object') {
      out[key] = clone(value);
    } else {
      out[key] = value;
    }
  }
  return out;
}

export function makePulley(xml, options) {
  if(!options) options = {};
  const types = options.types || ['opentag', 'closetag', 'text'];
  const opentag = options.opentag || (function() {
    for(let i = 0; i < types.length; ++i) {
      if(types[i] === 'opentagstart') {
        return 'opentagstart';
      }
      return 'opentag';
    }
  })();
  if(opentag !== 'opentag' && opentag !== 'opentagstart') {
    throw Error(`options.opentag must be an opening tag type, not ${opentag}!`);
  }
  const queue = [];
  const parser = saxParser(true, {
    xmlns: options.xmlns,
    position: false
  });
  const skipWS = options.skipWhitespaceOnly;
  const trim = options.trim, normalize = options.normalize;
  const textOpts = (t) => {
    if(trim)
      t = t.trim();
    if(normalize)
      t = t.replace(/\s+/g, " ")
    return t;
  };
  let text = null, rawText = null, wsText = null, wsRawText = null;
  const flushText = () => {
    if(skipWS && wsText !== null) {
      queue.push({
        type: 'wstext',
        text: wsText,
        rawText: wsRawText,
        wsHasNext: text !== null
      });
      wsText = wsRawText = null;
    }
    if(text !== null) {
      queue.push({
        type: 'text',
        text,
        rawText
      });
      text = rawText = null;
    }
  };
  parser.onerror = (err) => {
    throw err;
  };
  types.forEach((type) => {
    if(type === 'text') {
      parser.ontext = (t) => {
        const pt = textOpts(t);
        if(skipWS) {
          if(wsText) {
            wsText += pt; wsRawText += t;
          } else {
            wsText = pt; wsRawText = t;
          }
        }
        if(!skipWS || /\S/.test(t)) {
          if(text) {
            text += pt; rawText += t;
          } else {
            text = pt; rawText = t;
          }
        }
      };
      parser.oncdata = (t) => {
        if(text) {
          text += t; rawText += t;
        } else {
          text = rawText = t;
        }
      };
    } else if(type === 'comment') {
      parser.oncomment = (t) => {
        flushText();
        queue.push({
          type: 'comment',
          text: textOpts(t),
          rawText: t
        });
      }
    } else if(type === 'doctype') {
      parser.ondoctype = (t) => {
        flushText();
        queue.push({
          type: 'doctype',
          text: t
        });
      }
    } else if(type === 'closetag') {
      parser.onclosetag = (t) => {
        flushText();
        queue.push({
          type: 'closetag',
          name: t
        });
      }
    } else if(type === 'opencdata' || type === 'closecdata') {
      parser['on'+type] = (data) => {
        flushText();
        queue.push({ type: type });
      }
    } else if(isAllowedType(type)) {
      parser['on'+type] = (data) => {
        flushText();
        data = clone(data);
        data.type = type;
        queue.push(data);
      }
    } else {
      throw Error(`${type} isn't an allowed type!`);
    }
  });
  parser.write(xml).close();
  flushText();
  queue.reverse();

  return constructPulley(queue, skipWS, opentag);
}

function constructPulley(queue, skipWS, opentag, checkoutcb) {
  let self;

  const next = skipWS ?
    () => {
      let out;
      while((out = queue.pop()) && out.type === 'wstext') {  }
      return out;
    } :
    () => queue.pop();
  const peek = skipWS ?
    () => {
      for(let i = queue.length - 1; i >= 0; --i) {
        const v = queue[i];
        if(v.type !== 'wstext') return v;
      }
    } :
    () => queue[queue.length - 1];

  const nextText = () => {
    const v = queue[queue.length - 1];
    if(v && v.type === 'text') {
      return queue.pop();
    } else if(v && v.type === 'wstext') {
      queue.pop();
      if(v.wsHasNext) queue.pop();
      return { type: 'text', text: v.text, rawText: v.rawText };
    } else {
      return { type: 'text', text: '', rawText: '' };
    }
  };
  const peekText = () => {
    const v = queue[queue.length - 1];
    if(v && v.type === 'text') {
      return v;
    } else if(v && v.type === 'wstext') {
      return { type: 'text', text: v.text, rawText: v.rawText };
    } else {
      return { type: 'text', text: '', rawText: '' };
    }
  };

  const check = (type, error) => {
    const out = peek();
    assertType(out, type, error);
    return out;
  };
  const checkName = (name, type, wrongNameError, wrongTypeError) => {
    type = type || opentag;
    const out = peek();
    assertType(out, type, wrongTypeError || wrongNameError);
    assertName(out, name, wrongNameError);
    return out;
  };

  const expect = (type, error) => {
    const out = check(type, error);
    next();
    return out;
  };
  const expectName = (name, type, wrongNameError, wrongTypeError) => {
    const out = checkName(name, type, wrongNameError, wrongTypeError);
    next();
    return out;
  };

  const loop = (callback, endType) => {
    endType = endType || 'closetag';
    let node;
    while((node = peek()) && node.type !== endType) {
      if(callback(self))
        break;
    }
  };
  const loopTag = (callback, name) => {
    const tag = name ? expectName(name) : expect(opentag);
    let node;
    while((node = peek()) && node.type !== 'closetag') {
      callback(self, tag);
    }
    expectName(tag.name, 'closetag');
    return tag;
  };

  const skipTag = (name) => {
    return loopTag((pulley) => {
      const tag = pulley.peek();
      if(tag.type === opentag) {
        pulley.skipTag(tag.name);
      } else {
        pulley.next();
      }
    }, name);
  };

  const _checkoutcb = (queue2) => {
    queue = queue2;
    return self;
  };
  const checkin = () => constructPulley(queue.slice(), skipWS, opentag, _checkoutcb);
  const checkout = checkoutcb ?
    () => {
      const parent = checkoutcb(queue);
      queue = [];
      return parent;
    } :
    () => {
      throw Error("Can't check out a pulley that wasn't checked in!");
    };

  return self = {
    next,
    peek,
    nextText,
    peekText,
    check,
    checkName,
    expect,
    expectName,
    loop,
    loopTag,
    skipTag,
    checkin,
    checkout
  };
}

export function assertType(node, type, error) {
  if(node === undefined) {
    throw error || Error(`Expected ${type}; got end of file!`);
  } else if(node.type !== type) {
    throw error || Error(`Expected ${type}; got ${node.type}: ${nodeRepr(node)}!`);
  }
}
export function assertName(tag, name, error) {
  if(tag.name !== name) {
    throw error ||
          Error(`${tag.type} had name ${tag.name} instead of ${name}!`);
  }
}

export function nodeRepr(tag) {
  switch(tag.type) {
    case 'text': case 'comment': return `"${tag.text}"`;
    case 'opentag': case 'opentagstart': return `<${tag.name}>`;
    case 'closetag': return `</${tag.name}>`;
    case 'doctype': return `<!${tag.text}>`;
    case 'processinginstruction': return `<?${tag.name} ${tag.body}?>`;
    case 'attribute': return `${tag.name}="${tag.value}"`;
    default:
  }
}
<|endoftext|>